Jersey 开发RESTful(十八) Springboot集
【原创文章,转载请注明原文章地址,谢谢!】
在本节中,我们将介绍Springboot对Jersey的集成。Springboot简化了太多的第三方框架集成,在Springboot中使用Jersey是非常简单的事情。
Springboot支持Jersey1.x和Jersey2.x,我们这里只介绍Springboot对Jersey2.x的支持。因为我们前面介绍了Spring对Jersey有原生的集成策略,所以springboot对jersey的集成变得非常简单。
第一步,引入Springboot对jersey的starter包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
第二步,Springboot需要对Jersey的配置对象,有三种配置方式,第一种方式创建一个自定义的ResourceConfig,第二种方式,返回一个ResourceConfig类型的@Bean,第三种方式,配置一组ResourceConfigCustomizer对象;我们分别来看看。在测试之前,我们还是准备好我们的服务对象和资源类:
public interface ISomeService {
void sayHi(String msg);
}
@Service
public class SomeServiceImpl implements ISomeService {
@Override
public void sayHi(String msg) {
System.out.println(msg);
}
}
接下来准备我们的资源类:
@Component
@Path("resource")
public class SpringbootResource {
@Autowired
private ISomeService someService;
@Path("sayhi")
@GET
public String sayHi(@QueryParam("msg") String msg) {
this.someService.sayHi(msg);
return "success";
}
}
这三段代码非常简单,就不做过多解释了。接下来看看我们Springboot的主配置对象:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
new Application()
.configure(new SpringApplicationBuilder(Application.class))
.run(args);
}
}
我这里使用的是Springboot提供的SpringBootServletInitializer类启动的应用,当然在main方法中也可以使用最简单的SpringApplication.run(Application.class, args)来启动也行。
创建自定义ResourceConfig:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(SpringbootResource.class);
}
}
只需要保证JerseyConfig在Application类能够扫描的包下即可。
这个时候发送测试请求:
localhost:8080/resource/sayhi?msg=wolfcode即可。
这个地方注意两点,
- Springboot默认把Jersey的根路径映射在/*上的;这个可以通过几种方式来配置,对于自定义的ResourceConfig方式来说,只需要在类上面添加一个@ApplicationPath注解即可:
@Component
@ApplicationPath("webapi")
public class JerseyConfig extends ResourceConfig {
那么我们的资源地址就变为了:
localhost:8080/webapi/resource/sayhi?msg=wolfcode
- Springboot建议在使用ResourceConfig添加资源类的时候,不要使用ResourceConfig类的packages方法去自动扫描,建议还是手动添加。官方的解释为:
Jersey’s support for scanning executable archives is rather limited. For example, it cannot scan for endpoints in a package found in WEB-INF/classes when running an executable war file. To avoid this limitation, the packages method should not be used and endpoints should be registered individually using the register method
即使用Jersey的packages是比较局限的,比如在应用运行在war包中的时候,就不能扫描到其中的包。所以建议单独的为每一个资源类独立使用register方法注册。
ResourceConfig类型的@Bean
第二种方式,使用@Bean创建一个ResourceConfig类实例即可。注释掉上节中的JerseyConfig类,我们只需要修改一下Appication类,添加方法:
@Bean
public ResourceConfig resourceConfig() {
ResourceConfig config = new ResourceConfig();
config.register(SpringbootResource.class);
return config;
}
即可。但是在这种情况下,想要配置Jersey的基础路径,就需要在application.properties文件中配置一个
spring.jersey.application-path=webapi
即可。
使用ResourceConfigCustomizer
Springboot提供了一个ResourceConfigCustomizer接口,让我们更灵活的对ResourceConfig对象进行配置。要使用该接口,我们先注释掉上面两节的相关代码,然后创建一个类:
@Component
public class MyResourceConfigCustomizer implements ResourceConfigCustomizer {
@Override
public void customize(ResourceConfig config) {
config.register(SpringbootResource.class);
}
}
该接口很简单,传入一个ResourceConfig实例,我们就可以针对这个实例进行相关配置。但是要让这个传入的config生效,我们还需要在Application类中提供一个基础的ResourceConfig类即可:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Bean
public ResourceConfig resourceConfig() {
return new ResourceConfig();
}
public static void main(String[] args) {
new Application()
.configure(new SpringApplicationBuilder(Application.class))
.run(args);
}
}
这种方式对比第二种方式的好处在于,我们可以把资源类的注册,过滤器,拦截器,Entity Provider,Feature等不同类型的组件注册从主类中分开,在代码管理上会更加清晰。
其他细节
1,Jersey和Springboot的集成有两种方式,一种是使用Filter的方式注册,一种是使用Servlet的方式注册,默认使用的是Servlet的方式,也可以通过spring.jersey.type=filter或者spring.jersey.type=servlet来控制。具体的代码可以参考JerseyAutoConfiguration类中的:
@Bean
@ConditionalOnMissingBean(name = "jerseyFilterRegistration")
@ConditionalOnProperty(prefix = "spring.jersey", name = "type", havingValue = "filter")
public FilterRegistrationBean jerseyFilterRegistration() {
@Bean
@ConditionalOnMissingBean(name = "jerseyServletRegistration")
@ConditionalOnProperty(prefix = "spring.jersey", name = "type", havingValue = "servlet", matchIfMissing = true)
public ServletRegistrationBean jerseyServletRegistration() {
从这两段代码我们也能看出来,当使用的是Filter的时候,Springboot实际上注册了一个名字为jerseyFilterRegistration的FilterRegistrationBean;而使用的是Servlet的时候,Springboot实际上注册了一个名字为jerseyServletRegistration的ServletRegistrationBean。那么这些都是如果我们要更进一步定制Jersey启动方式可以扩展的点。
2,如果使用Servlet的方式启动,默认是使用的延迟启动。我们可以通过jerseyServletRegistration方法的代码就可以看出来:
registration.setName(getServletRegistrationName());
registration.setLoadOnStartup(this.jersey.getServlet().getLoadOnStartup());
return registration;
第二句代码setLoadOnStartup方法,调用的是this.jersey.getServlet().getLoadOnStartup(),而这个地方的jersey就是JerseyProperties对象:
@ConfigurationProperties(prefix = "spring.jersey")
public class JerseyProperties {
其中servlet的类代码为:
public static class Servlet {
/**
* Load on startup priority of the Jersey servlet.
*/
private int loadOnStartup = -1;
public int getLoadOnStartup() {
return this.loadOnStartup;
}
public void setLoadOnStartup(int loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
}
可以看到,默认值为-1;那么我们只需要在application.properties中配置spring.jersey.servlet.loadOnStartup=1即可迫切让Jersey的Servlet实例化。
更多的配置,建议有兴趣的童鞋可以去看看org.springframework.boot.autoconfigure.jersey包中的两个类:
- JerseyProperties
- JerseyAutoConfiguration
代码非常简单,但是能看出很多配置,比如不管针对Filter的方式还是Servlet的方式都可以使用spring.jersey.init.*来为Jersey添加初始化配置参数:
@ConfigurationProperties(prefix = "spring.jersey")
public class JerseyProperties {
/**
* Init parameters to pass to Jersey via the servlet or filter.
*/
private Map<String, String> init = new HashMap<String, String>();
小结
Springboot集成Jersey总体来说还是非常简单。只是额外想说的就是,针对Springboot集成第三方框架,还是希望童鞋们能够理解Springboot的自动配置原理,那么看看相关代码,那么该怎么集成,该怎么配置,有哪些配置,有哪些扩展点都非常简单了。
至此,Jersey的普通使用我们就介绍到这里。当然,Jersey还有非常多非常多的细节的点,比如URI构造,比如WADL支持,比如基于Hyperlink的应用构建,比如基础的权限控制,OAuth2.0的支持,比如Jersey应用的监控,异步请求的支持,基于JSR-330的验证等,因为使用的频率和篇幅的问题,我们就后面有机会再介绍。
当然,如果通过Jersey这系列的文章,当你对Jersey有了一个初步的理解之后,通过Jersey的官方文档https://jersey.github.io/documentation/latest/user-guide.html学习相关内容也是非常轻松的。
后面我们将开始介绍REST API文档生成相关内容。
WechatIMG7.jpeg