非Spring Boot/SpringRest环境下Spring 5 MVC集成Jersey 2.x及Autowired问题求助
Hey there, let's fix that frustrating @Autowired null issue you're facing! The root cause almost always boils down to Jersey not using Spring's bean container to manage its resources—so let's walk through a step-by-step integration that ensures proper dependency injection works as expected.
1. Core Dependency Setup (Maven)
First, make sure you have the right dependencies in your pom.xml. The key here is the jersey-spring5 module, which bridges Jersey and Spring 5, plus we'll exclude conflicting Spring dependencies from Jersey's package to avoid version mismatches.
<dependencies> <!-- Spring 5 MVC Core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.24</version> </dependency> <!-- Jersey 2.x Core --> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>2.41</version> </dependency> <!-- Critical: Jersey-Spring 5 Integration --> <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-spring5</artifactId> <version>2.41</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2. Web.xml Configuration
We need to configure both Spring's DispatcherServlet (for MVC) and Jersey's ServletContainer (for API endpoints), making sure they use the same Spring context.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- Spring MVC DispatcherServlet --> <servlet> <servlet-name>springMvcDispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvcDispatcher</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <!-- Jersey Servlet (handles API requests) --> <servlet> <servlet-name>jerseyServlet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.yourpackage.config.JerseyConfig</param-value> </init-param> <!-- Key: Tell Jersey to use Spring's existing context --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc-config.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jerseyServlet</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> </web-app>
3. Spring MVC Configuration (spring-mvc-config.xml)
Enable component scanning for your services and controllers, and turn on Spring MVC's annotation support.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- Scan for Spring-managed beans (services, MVC controllers) --> <context:component-scan base-package="com.yourpackage.service, com.yourpackage.mvc.controller"/> <!-- Enable Spring MVC annotation-driven features --> <mvc:annotation-driven/> </beans>
4. Jersey Configuration Class
Create a ResourceConfig subclass to register Jersey's Spring component provider and scan for your Jersey API resources.
package com.yourpackage.config; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.spring5.SpringComponentProvider; import org.springframework.context.annotation.Configuration; @Configuration public class JerseyConfig extends ResourceConfig { public JerseyConfig() { // Critical: Register Spring component provider to wire dependencies register(SpringComponentProvider.class); // Scan for Jersey resource classes in your API package packages("com.yourpackage.jersey.resource"); } }
5. Example Service & Jersey Resource
UserService Interface & Implementation
package com.yourpackage.service; public interface UserService { String getUserNameById(Long id); }
package com.yourpackage.service.impl; import com.yourpackage.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override public String getUserNameById(Long id) { return "User_" + id; } }
Jersey Resource with @Autowired
package com.yourpackage.jersey.resource; import com.yourpackage.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/users") public class UserResource { // @Autowired will now work because Jersey uses Spring's container @Autowired private UserService userService; @GET @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) public String getUser(@PathParam("id") Long id) { // No more null pointer here! return "{\"name\": \"" + userService.getUserNameById(id) + "\"}"; } }
Key Fixes for the Null @Autowired Issue
- Use
jersey-spring5: This module is non-negotiable—it connects Jersey to Spring's application context. - Share the Spring Context: Ensure Jersey's servlet uses the same
contextConfigLocationas Spring MVC, so both use the same bean container. - Register
SpringComponentProvider: This tells Jersey to delegate bean creation and dependency injection to Spring. - Avoid Duplicate Scanning: Make sure your Jersey resources aren't scanned by both Spring's
component-scanand Jersey'spackages—this can create two instances (one managed by Spring, one by Jersey, which won't have injected dependencies).
Once you set this up, fire up your app and hit http://localhost:8080/your-app/api/users/1—you'll get a valid JSON response, and your UserService will no longer be null!
内容的提问来源于stack exchange,提问作者Dima Shtef

