将spring boot与RESTEasy集成
我正在尝试一个Spring引导应用程序的原型。我来自Guice JAX-RS应用程序,因此与Spring MVC相比,我更喜欢标准JAX-RS注释。我已经让Jetty站起来并提供服务:将spring boot与RESTEasy集成,spring,spring-boot,jax-rs,resteasy,Spring,Spring Boot,Jax Rs,Resteasy,我正在尝试一个Spring引导应用程序的原型。我来自Guice JAX-RS应用程序,因此与Spring MVC相比,我更喜欢标准JAX-RS注释。我已经让Jetty站起来并提供服务: @Configuration @Import({ResteasyBootstrap.class, SpringBeanProcessorServletAware.class, HttpServletDispatcher.class}) public class EmbeddedJetty { @Bean
@Configuration
@Import({ResteasyBootstrap.class, SpringBeanProcessorServletAware.class, HttpServletDispatcher.class})
public class EmbeddedJetty {
@Bean
@Singleton
public EmbeddedServletContainerFactory servletContainer() {
JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
return factory;
}
}
然而,我就是不知道如何正确连接RESTEasy。使用上面的SpringBeanProcessorServletAware
时,似乎在使用ServletContextAware
之前,ServletContext
没有通过ServletContextAware注入:
java.lang.NullPointerException: null
at org.jboss.resteasy.plugins.spring.SpringBeanProcessorServletAware.getRegistry(SpringBeanProcessorServletAware.java:30)
at org.jboss.resteasy.plugins.spring.SpringBeanProcessor.postProcessBeanFactory(SpringBeanProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:680)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
我还尝试了使用SpringContextLoaderListener,但这似乎与SpringBoot注释ConfigEmbeddedWebApplicationContext类冲突
我使用的是spring boot 1.3.3和spring framework 4.3.0。rc1这里是一个完整的工作示例
首先,一个JAX-RS端点示例:
@Path("/api")
public class SampleResource {
@GET
@Path("/sample")
@Produces(MediaType.APPLICATION_JSON)
public String getSample() {
return "Some JSON";
}
}
接下来,是加载所有端点的JAX-RS配置类
import javax.ws.rs.core.Application;
public class RestEasyConfig extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(SampleRest.class);
return classes;
}
}
导入javax.ws.rs.core.Application;
公共类RestEasyConfig扩展了应用程序{
@凌驾
public Set>classes=new HashSet();
添加(sampleest.class);
返回类;
}
}
最后,在Spring配置中,初始化RESTEast过滤器并通知框架它的存在
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.jboss.resteasy.plugins.server.servlet.FilterDispatcher;
...
@Bean
public FilterRegistrationBean filterRegistrationBean() {
Map<String, String> initParams = new HashMap<>();
initParams.put("javax.ws.rs.Application", RestEasyConfig.class.getCanonicalName());
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new FilterDispatcher());
registrationBean.setInitParameters(initParams);
return registrationBean;
}
import org.springframework.boot.context.embedded.FilterRegistrationBean;
导入org.jboss.resteasy.plugins.server.servlet.FilterDispatcher;
...
@豆子
公共过滤器注册bean过滤器注册bean(){
Map initParams=new HashMap();
initParams.put(“javax.ws.rs.Application”,RestEasyConfig.class.getCanonicalName());
FilterRegistrationBean registrationBean=新的FilterRegistrationBean();
setFilter(新的FilterDispatcher());
setInitParameters(initParams);
返回注册bean;
}
您的端点应该已启动并正在运行。如果类路径上缺少FilterDispatcher类,请将库添加到生成描述符中
另一个答案是,您的资源不能作为SpringBean使用,此自动配置将正确集成它们:
配置类:
@Configuration
@ConditionalOnWebApplication
public class RestEasyAutoConfigurer {
private Environment environment;
@Bean(name = "resteasyDispatcher")
public ServletRegistrationBean resteasyServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HttpServletDispatcher(), getPrefix()
+ "/*");
registrationBean.setInitParameters(ImmutableMap.of("resteasy.servlet.mapping.prefix", "/rs/")); // set prefix here
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
@Bean(destroyMethod = "cleanup")
public static RestEasySpringInitializer restEasySpringInitializer() {
return new RestEasySpringInitializer();
}
@Bean
// use Spring Boot configured Jackson
public CustomResteasyJackson2Provider jackson2Provider(ObjectMapper mapper) {
return new CustomResteasyJackson2Provider(mapper);
}
public static class RestEasySpringInitializer
implements
ServletContextInitializer,
ApplicationContextAware,
BeanFactoryPostProcessor {
private ResteasyDeployment deployment;
private ConfigurableApplicationContext applicationContext;
private ConfigurableListableBeanFactory beanFactory;
public void cleanup() {
deployment.stop();
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
ListenerBootstrap config = new ListenerBootstrap(servletContext);
deployment = config.createDeployment();
deployment.start();
servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory());
servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher());
servletContext.setAttribute(Registry.class.getName(), deployment.getRegistry());
SpringBeanProcessor processor = new SpringBeanProcessor(deployment.getDispatcher(),
deployment.getRegistry(), deployment.getProviderFactory());
processor.postProcessBeanFactory(beanFactory);
applicationContext.addApplicationListener(processor);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
}
而杰克逊的提供者:
@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CustomResteasyJackson2Provider extends ResteasyJackson2Provider {
private ObjectMapper mapper;
public CustomResteasyJackson2Provider(ObjectMapper mapper) {
this.mapper = mapper;
}
@Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
return Optional.ofNullable(_mapperConfig.getConfiguredMapper()).orElse(mapper);
}
}
@Provider
@使用({“application/*+json”,“text/json”})
@产生({“application/*+json”,“text/json”})
公共类CustomResteasyJackson2Provider扩展了ResteasyJackson2Provider{
私有对象映射器映射器;
公共CustomResteasyJackson2Provider(对象映射器映射器){
this.mapper=mapper;
}
@凌驾
公共对象映射器locateMapper(类类型,MediaType,MediaType){
返回可选的.ofNullable(_-mapperConfig.getConfiguredMapper()).orElse(映射器);
}
}
注意:这是Spring Boot 1.3.3/RESTEasy 3.0.16的工作配置,您可以使用RESTEasy Spring Boot starter。以下是您的操作方法:
添加POM依赖项
将下面的Maven依赖项添加到Spring引导应用程序pom文件中
<dependency>
<groupId>com.paypal.springboot</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.1.1-RELEASE</version>
<scope>runtime</scope>
</dependency>
注册JAX-RS资源和提供者
只要将它们定义为Springbean,它们就会自动注册。请注意,JAX-RS资源可以是单例的,也可以是请求范围的,而JAX-RS提供者必须是单例的
.退房。这是一个启动开发者写的谢谢!我尝试过这个方法,但正如Jeff S所说,这意味着RESTEasy资源不是Spring生命周期的一部分——例如,no@PostConstruct annotations fire。请记住,“另一个答案不会将您的资源作为Spring bean”,这是不正确的。下面我的回答中提到的RESTEasy Spring引导状态器功能齐全,包括自动将每个资源和提供者注册为SpringBean,此外还自动注册JAX-RS应用程序子类。
package com.test;
import org.springframework.stereotype.Component;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@Component
@ApplicationPath("/sample-app/")
public class JaxrsApplication extends Application {
}