非Boot Spring项目迁移至Spring 6+Jakarta后RESTEasy注入空指针问题
将非Spring Boot的Spring Framework项目迁移至Spring 6、Java 17及Jakarta规范后,更换兼容Spring 6的RESTEasy依赖,RESTEasy API可正常访问,但@Autowired注解注入的类出现java.lang.NullPointerException。
错误日志
RESTEASY002375: Error processing request POST /application/api/rest/rjob/startjob - com.application.rest.server.JobServerProvider.startJob --- o.j.r.c.p.DefaultExceptionMapper:90 --- [http-nio-8080-exec-1]
java.lang.NullPointerException: Cannot invoke "com.application.rest.server.RequestValidator.isRequestValid(jakarta.servlet.http.HttpServletRequest)" because "this.requestValidator" is null
依赖变更
旧RESTEasy依赖
- groupId:
org.jboss.resteasy,artifactId:resteasy-jaxrs - groupId:
org.jboss.resteasy,artifactId:resteasy-spring
新RESTEasy依赖
- groupId:
org.jboss.resteasy,artifactId:resteasy-core - groupId:
org.jboss.resteasy,artifactId:resteasy-servlet-initializer - groupId:
org.jboss.resteasy,artifactId:resteasy-client - groupId:
org.jboss.resteasy,artifactId:resteasy-client-api
配置变更
旧配置
web.xml
<servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/appContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
appContext.xml
<import resource="classpath:springmvc-resteasy.xml"/> <context:component-scan base-package="com.application.ws"/> <context:component-scan base-package="com.application.rest"/>
新配置
web.xml
<!-- Resteasy JAX-RS Servlet --> <servlet> <servlet-name>resteasy-servlet</servlet-name> <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/appContext.xml</param-value> </init-param> <init-param> <param-name>jakarta.ws.rs.Application</param-name> <param-value>com.application.rest.server.RestServerApplication</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>resteasy-servlet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/appContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
appContext.xml
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/> <!-- <import resource="classpath:springmvc-resteasy.xml"/> --> <bean id="resteasyDispatcher" class="org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher"/> <context:component-scan base-package="com.application.ws"/> <context:component-scan base-package="com.application.rest"/>
1. 补充RESTEasy与Spring整合的核心依赖
新依赖中缺少了适配Spring 6的resteasy-spring6组件,它是实现RESTEasy与Spring上下文打通的关键。没有该依赖时,RESTEasy会自行创建JAX-RS资源实例,无法访问Spring容器中的Bean,导致@Autowired注入失效。
添加以下依赖(版本与其他RESTEasy组件保持一致):
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-spring6</artifactId> <version>${resteasy.version}</version> </dependency>
2. 调整配置,确保RESTEasy复用Spring上下文
当前配置同时启动了RESTEasy的HttpServletDispatcher和Spring的DispatcherServlet,两者上下文完全隔离,导致RESTEasy管理的资源无法获取Spring Bean。可选择以下两种方案:
方案一:恢复基于Spring DispatcherServlet的配置
移除web.xml中独立的resteasy-servlet配置,保留原有的Spring DispatcherServlet处理所有REST请求,同时恢复Spring与RESTEasy的整合配置:
修改后的web.xml
<servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/appContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>
修改后的appContext.xml
<import resource="classpath:springmvc-resteasy.xml"/> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/> <context:component-scan base-package="com.application.ws"/> <context:component-scan base-package="com.application.rest"/>
方案二:让RESTEasy Servlet使用Spring管理的资源
如果要保留HttpServletDispatcher,需配置RESTEasy从Spring容器中获取资源实例:
- 在appContext.xml中添加RESTEasy Spring整合处理器:
<bean class="org.jboss.resteasy.plugins.spring.SpringBeanProcessor"/>
- 确保
JobServerProvider等JAX-RS资源类添加了@Component(或@Service)注解,被Spring的component-scan扫描到:
@Component @Path("/rjob") public class JobServerProvider { @Autowired private RequestValidator requestValidator; // 业务方法 }
3. 验证初始化日志
启动项目后,检查日志确认Spring容器成功初始化RequestValidator和JobServerProvider,且RESTEasy正确识别了Spring管理的资源实例。
内容的提问来源于stack exchange,提问作者Amaan

