Jersey框架相关

介绍

Jersey是一个REST框架,类似 SpringMVC,必须运行在Servlet容器中,如Tomcat或Jetty。

使用

在SpringBoot内嵌Tomcat容器中使用

<properties>
   <java.version>1.8</java.version>
   <jersey2.version>2.26</jersey2.version>
   <jaxrs.version>2.1</jaxrs.version>
</properties>
<dependencies>
    <!-- JAX-RS -->
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>${jaxrs.version}</version>
    </dependency>
    <!-- Jersey 2.26 -->
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>${jersey2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>${jersey2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

注意要使用JDK1.8,不能使用JDK11,使用jersey的高版本的话,jar包版本冲突,暂时没找到解决方案。

server:
  port: 9999
  servlet:
    context-path: /demo-jersey-server

spring:
  application:
    name: demo-jersey-server

配置SpringBoot启动类

@SpringBootApplication
public class JerseyServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(JerseyServerApplication.class, args);
    }

}
@Configuration
public class JerseyConfig {

    @Bean
    public ServletRegistrationBean<ServletContainer> jerseyServlet() {
        ServletRegistrationBean<ServletContainer> registrationBean = new ServletRegistrationBean<>();
        ResourceConfig resourceConfig = new ResourceConfig();
        resourceConfig.packages("com.imooc.demojerseyserver.jersey");//配置包扫描路径
        registrationBean.setServlet(new ServletContainer(resourceConfig));
        registrationBean.addUrlMappings("/testJersey/*");
        return registrationBean;
    }
}

配置ServletContainer,这是一个Servlet,类似于SpringMVC中的DispatcherServlet。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodsInfo {

    private String goodsId;
    private String goodsName;
}
@Path("/jersey")
public class JerseyController {

    //返回字符串格式的数据
    @GET
    @Path("/hello")
    public String hello() {
        return "hello jersey";
    }

    //返回json格式的数据
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/hello2")
    public GoodsInfo goodsInfo() {
        return new GoodsInfo("001", "矿泉水");
    }
}

请求地址为

http://localhost:9999/demo-jersey-server/testJersey/jersey/hello2

在Jetty容器中使用

<dependency>
   <groupId>org.glassfish.jersey.containers</groupId>
   <artifactId>jersey-container-jetty-http</artifactId>
   <version>${jersey2.version}</version>
</dependency>

继承上面的maven依赖

@Path("/jersey")
public class JerseyController {

    @GET
    @Path("/hello")
    public String hello() {
        return "hello jersey";
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/hello2")
    public GoodsInfo goodsInfo() {
        return new GoodsInfo("001", "矿泉水");
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodsInfo {

    private String goodsId;
    private String goodsName;
}
public class TestJerseyServer {
    public static void main(String[] args) {
        ResourceConfig resourceConfig = new ResourceConfig();
        resourceConfig.packages("com.imooc.sourcecode2.jersey");
        JettyHttpContainerFactory.createServer(URI.create("http://localhost:9998/"), resourceConfig);
    }
}

请求地址为

http://localhost:9998/jersey/hello2

原理分析

扫描路由的流程

  1. 创建ServletContainer对象
  2. Servlet初始化,调用init()方法
  3. 创建WebComponent对象
  4. 根据ResourceConfig创建ApplicationHandler对象,ResourceConfig中保存着包扫描路径
  5. ApplicationHandler的initialize()方法
  6. RuntimeConfigConfigurator的init()方法,在这个过程中会调用RuntimeConfig的getClasses()方法,继续调用scanClasses()方法
  7. AnnotationAcceptingListener接收@Path注解和@Provider注解,使用PackageNamesScanner来扫描class,内部使用FileSchemeResourceFinderFactory和FileSchemeScanner来做具体扫描
  8. AnnotationAcceptingListener内部使用ASM框架来解析class,判断是否包含@Path等注解
  9. ResourceBagConfigurator的init()方法
  10. 根据扫描到的class创建Resource对象,在这个过程中会扫描方法,扫描@GET,@Path等注解
  11. 所有的路由数据最终保存在ServerBootstrapBag对象中,继续保存在ApplicationHandler的ServerRuntime字段中。

处理请求的流程

  1. ServletContainer的service()方法
  2. ApplicationHandler的handle()方法
  3. ServerRuntime的process()方法
  4. 通过Stages获取到Endpoint,实际类型为ResourceMethodInvoker,调用它的apply()方法,具体查找路由类和方法由RoutingStage来处理,将匹配到的handler放到RequestProcessingContext上下文中
  5. ResourceMethodDispatcher的dispatch()方法
  6. dispatcher分发器具体类型为TypeOutInvoker,内部通过反射来执行方法

参考

Jersey 开发RESTful(七)Jersey快速入门

posted @ 2023-08-21 22:02  strongmore  阅读(132)  评论(0编辑  收藏  举报