介绍
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
原理分析
扫描路由的流程
- 创建ServletContainer对象
- Servlet初始化,调用init()方法
- 创建WebComponent对象
- 根据ResourceConfig创建ApplicationHandler对象,ResourceConfig中保存着包扫描路径
- ApplicationHandler的initialize()方法
- RuntimeConfigConfigurator的init()方法,在这个过程中会调用RuntimeConfig的getClasses()方法,继续调用scanClasses()方法
- AnnotationAcceptingListener接收@Path注解和@Provider注解,使用PackageNamesScanner来扫描class,内部使用FileSchemeResourceFinderFactory和FileSchemeScanner来做具体扫描
- AnnotationAcceptingListener内部使用ASM框架来解析class,判断是否包含@Path等注解
- ResourceBagConfigurator的init()方法
- 根据扫描到的class创建Resource对象,在这个过程中会扫描方法,扫描@GET,@Path等注解
- 所有的路由数据最终保存在ServerBootstrapBag对象中,继续保存在ApplicationHandler的ServerRuntime字段中。
处理请求的流程
- ServletContainer的service()方法
- ApplicationHandler的handle()方法
- ServerRuntime的process()方法
- 通过Stages获取到Endpoint,实际类型为ResourceMethodInvoker,调用它的apply()方法,具体查找路由类和方法由RoutingStage来处理,将匹配到的handler放到RequestProcessingContext上下文中
- ResourceMethodDispatcher的dispatch()方法
- dispatcher分发器具体类型为TypeOutInvoker,内部通过反射执行方法