java rabbitTemplate 如何路由方式监听 java实现路由器_应用程序

actix-web 提供了各种原语,以使用 Rust 程序设计语言构建 web 服务器和应用程序。它提供路由、中间件、预处理请求,以及响应的后置处理等。
所有 actix-web 服务器都是围绕 App(应用程序)实例构建的,其用于注册资源路由和中间件。另外,在同一作用域(scope)中,actix-web 服务器也存储所有处理程序之间共享的应用程序状态。

java rabbitTemplate 如何路由方式监听 java实现路由器_用java编写一个计算器程序_02

应用程序的作用域(scope)充当所有路由的命名空间,也就是说,特定的应用程序作用域内,所有路由都具有相同的 url 路径前缀。应用程序的路由前缀始终包含前导斜杠 “/”;如果提供的前缀不包含前导斜杠 “/”,则会自动补入该前缀。除了前导斜杠 “/”,路由前缀也应该包含路径值。

比如,应用程序的作用域为 /app,即路径前缀为 /app。那么,路径为 /app、/app/,或者 /app/test 的请求都可以匹配;但是,路径 /application 不能匹配。

use actix_web::{web, App, HttpServer, Responder};async fn index() -> impl Responder {    "Hello world!"}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new().service(            // prefixes all resources and routes attached to it...            web::scope("/app")                // ...so this handles requests for `GET /app/index.html`                .route("/index.html", web::get().to(index)),        )    })    .bind("127.0.0.1:8080")?    .run()    .await}

上述例子中,创建了具有 /app 前缀和 index.html 页面资源的应用程序。此资源可通过 url 路径 /app/index.html 获得。

要获取更多信息,请参阅 URL 调度 - 使用作用域前缀一节。

状态(state)

应用程序状态(state)被同一作用域(scope)内的所有路由和资源共享。可以使用数据提取器 web::Data 访问状态(state),其中泛型参数 T 表示状态类型。另外,中间件也可以访问状态。

让我们编写一个简单的应用程序,并将应用程序名称存储在状态中:

use actix_web::{get, web, App, HttpServer};// This struct represents statestruct AppState {    app_name: String,}#[get("/")]async fn index(data: web::Data) -> String {    let app_name = &data.app_name; //     format!("Hello {}!", app_name) // }

并在 App 初始化时传入状态(state),然后启动应用程序:

#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .data(AppState {                app_name: String::from("Actix-web"),            })            .service(index)    })    .bind("127.0.0.1:8080")?    .run()    .await}

在应用程序中,可以注册任意数量的状态(state)类型。

共享可变状态

HttpServer 接受应用程序工厂,而非应用程序实例。HttpServer 为每个线程构造一个应用程序实例。因此,必须多次构造应用程序数据。如果你想在不同的线程之间共享数据,应该使用一个可共享的对象,例如 Send + Sync。

web::Data 内部使用 Arc(原子引用计数器)。因此,为了避免创建两个 Arc(原子引用计数器),我们应该在使用 App::app_data() 方法注册数据之前,先行创建数据。

在下面的示例中,我们将编写一个应用程序,其具有可变的、共享的状态(state)。首先,我们定义状态并创建处理程序:

use actix_web::{web, App, HttpServer};use std::sync::Mutex;struct AppStateWithCounter {    counter: Mutex, // }async fn index(data: web::Data) -> String {    let mut counter = data.counter.lock().unwrap(); //     *counter += 1; //     format!("Request number: {}", counter) // }

然后,在 App 中注册数据:

#[actix_web::main]async fn main() -> std::io::Result {    let counter = web::Data::new(AppStateWithCounter {        counter: Mutex::new(0),    });    HttpServer::new(move || {        // move counter into the closure        App::new()            // Note: using app_data instead of data            .app_data(counter.clone()) //             .route("/", web::get().to(index))    })    .bind("127.0.0.1:8080")?    .run()    .await}

使用作用域组合应用程序

web::scope() 方法允许设置资源组前缀。此作用域表示一个预添加的资源前缀——在由资源配置添加的所有资源模式中,该前缀将被预先附加。这有助于将一组新编写的路由挂载到不同位置,从而与以前开发者设计的位置分离,但仍然保持相同的资源名称。

我们来看实际例子:

#[actix_web::main]async fn main() {    let scope = web::scope("/users").service(show_users);    App::new().service(scope);}

在上面的示例中,show_users 路由的有效路由模式将是 /users/show,而非 /show,因为应用程序的 scope 参数将附加在模式前面。仅当 URL 路径为 /users/show 时,路由才将匹配。使用路由名称 show_users 调用函数 HttpRequest.url_for(),它将生成具有相同路径的 URL。

应用程序卫语句及虚拟主机

可以将卫语句看作是一个简单的函数,它接受 request 对象引用,并返回 true 或者 false。从形式上讲,卫语句是实现了 Guard trait 的任何对象。actix-web 提供了多种卫语句,要详细了解,请查看 API 文档的函数部分。

Header 是 actix-web 提供的卫语句之一,它可以用作基于请求头信息的过滤器。

#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .service(                web::scope("/")                    .guard(guard::Header("Host", "www.rust-lang.org"))                    .route("", web::to(|| HttpResponse::Ok().body("www"))),            )            .service(                web::scope("/")                    .guard(guard::Header("Host", "users.rust-lang.org"))                    .route("", web::to(|| HttpResponse::Ok().body("user"))),            )            .route("/", web::to(|| HttpResponse::Ok()))    })    .bind("127.0.0.1:8080")?    .run()    .await}

配置

为了简洁和可重用,App 和 web::Scope 均提供了 configure 方法,此函数用于将配置的部分移动到不同的模块甚至库中。例如,资源的某些配置可以移动到其它模块。

use actix_web::{web, App, HttpResponse, HttpServer};// this function could be located in a different modulefn scoped_config(cfg: &mut web::ServiceConfig) {    cfg.service(        web::resource("/test")            .route(web::get().to(|| HttpResponse::Ok().body("test")))            .route(web::head().to(|| HttpResponse::MethodNotAllowed())),    );}// this function could be located in a different modulefn config(cfg: &mut web::ServiceConfig) {    cfg.service(        web::resource("/app")            .route(web::get().to(|| HttpResponse::Ok().body("app")))            .route(web::head().to(|| HttpResponse::MethodNotAllowed())),    );}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .configure(config)            .service(web::scope("/api").configure(scoped_config))            .route("/", web::get().to(|| HttpResponse::Ok().body("/")))    })    .bind("127.0.0.1:8080")?    .run()    .await}

上述示例的结果是:

/         -> "/"/app      -> "app"/api/test -> "test"

每一个 ServiceConfig 可以有自己的数据(data)、路由(route),以及服务(services)。

java rabbitTemplate 如何路由方式监听 java实现路由器_应用程序_03