Spring DI - REST 服务中的自动装配属性为空
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19745187/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring DI - Autowired property is null in a REST service
提问by diegosasw
I'm getting started with Spring DI, but I'm struggling with dependency injection and the worse part is that I'm not even sure why as it seems ok to me. Hopefully you guys can help me out!
我正在开始使用 Spring DI,但我在依赖注入方面苦苦挣扎,更糟糕的是,我什至不确定为什么,因为对我来说似乎没问题。希望大家帮帮我!
The problem is that a property annotated as @Autowiredis always null
问题是注释为@Autowired 的属性始终为空
I've got a few projects with Maven structure:
我有一些具有 Maven 结构的项目:
- com.diegotutor.lessondeliver
- com.diegotutor.utility
- com.diegotutor.lessondeliver
- com.diegotutor.utility
I'm running the examples over Tomcat 7
我正在 Tomcat 7 上运行示例
I'm using the following dependencies in my pom.xml:
我在我的中使用以下依赖项pom.xml:
- spring-context 3.2.4
- spring-web 3.2.4
- jersey-server 1.17.1
- jersey-core 1.17.1
- jersey-servlet 1.17.1
- 弹簧上下文 3.2.4
- 弹簧网 3.2.4
- 球衣服务器 1.17.1
- 球衣核心 1.17.1
- 球衣小服务程序 1.17.1
The simple idea is to have a RESTful service that through Dependency Injection is able to print out the value of a property located in a config file located at: D:\configuracion.conf.
简单的想法是拥有一个 RESTful 服务,通过依赖注入能够打印出位于以下配置文件中的属性值: D:\configuracion.conf.
At com.diegotutor.utilityI have the following interface:
在com.diegotutor.utility我有以下界面:
package com.diegotutor.utility;
public interface ConfigService {
public String getProperty(final String propertyName);
}
Implemented by:
实施者:
package com.diegotutor.utility.impl;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import com.diegotutor.utility.ConfigService;
public class PropertyFileConfigService implements ConfigService{
Properties prop;
public PropertyFileConfigService (final InputStream input) throws IOException {
if(input == null) {
throw new IllegalArgumentException("Input stream can't be null");
}
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService (final String fileName) throws IOException {
final FileInputStream input = new FileInputStream(fileName);
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService(final Reader input) throws IOException {
prop = new Properties();
prop.load(input);
}
public String getProperty(final String propertyName) {
return prop.getProperty(propertyName);
}
}
And at com.diegotutor.lessondeliverI have the RESTful service where I would like to use an injected instance of the ConfigService:
在com.diegotutor.lessondeliver我有 RESTful 服务,我想在其中使用 ConfigService 的注入实例:
package com.diegotutor.lessondeliver;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.diegotutor.utility.ConfigService;
@Path("/")
@Component
public class HelloWorld {
private static final Log log = LogFactory.getLog(HelloWorld.class);
@Autowired
private ConfigService configService;
@Path("/helloworld")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getHello() {
String host = configService.getProperty("host");
return "Hello World! HOST" + host;
// configService IS NULL!!
//SO IT THROWS A NULLPOINTER EXCEPTION WHEN INVOKING getProperty ON IT
}
}
Finally at /com.diegotutor.lessondeliver/src/main/webapp/WEB-INF/service-beans.xmlI have the following XML application context file, where I use the implementation of ConfigService (PropertyFileConfigService)injecting on it the path for the configuration file to read:
最后,/com.diegotutor.lessondeliver/src/main/webapp/WEB-INF/service-beans.xml我有以下 XML 应用程序上下文文件,我在其中使用了ConfigService (PropertyFileConfigService)在其上注入配置文件读取路径的实现:
<?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"
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">
<bean id="configService" class="com.diegotutor.utility.impl.PropertyFileConfigService">
<constructor-arg type="java.lang.String"
value="D:\configuracion.conf" />
</bean>
<context:component-scan base-package="com.diegotutor" />
</beans>
Obviously I have specified in the web.xmlof this com.diegotutor.lessondeliverweb app that I want service-beans.xmlas ConfigLocation and a listener ContextLoaderListener, and the RESTful service relies on ServletContainer
显然我已经在web.xml这个com.diegotutor.lessondeliverweb 应用程序的 中指定了我想要的service-beans.xmlConfigLocation 和一个 listener ContextLoaderListener,并且 RESTful 服务依赖于 ServletContainer
If I'm specifying context:component-scan to look for Components in com.diegotutoras suggested hereand I'm forcing object creation through Spring by not using any new Statement as suggested here, Why am I getting the annotated configService as null? Why Spring is unable to inject an instance of com.diegotutor.utility.impl.PropertyFileConfigService?
如果我com.diegotutor按照此处的建议指定 context:component-scan 来查找组件,并且我通过不使用此处建议的任何新语句来强制通过 Spring 创建对象,为什么我将带注释的 configService 获取为 null?为什么 Spring 无法注入 的实例com.diegotutor.utility.impl.PropertyFileConfigService?
Any help will be much appreciated!
任何帮助都感激不尽!
Thank you
谢谢
EDITED:
编辑:
As requested, my web.xml is as follows:
根据要求,我的 web.xml 如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>com.diegotutor.lessondeliver</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/service-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
回答by diegosasw
You were right! It seems that the problem is that Jersey is totally unaware of Spring and instantiates its own object. In order to make Jersey aware of Spring object creations (through dependency injection) I had to integrate Spring + Jersey.
你是对的!似乎问题在于 Jersey 完全不知道 Spring 并实例化了自己的对象。为了让 Jersey 了解 Spring 对象的创建(通过依赖注入),我必须集成 Spring + Jersey。
To integrate:
集成:
Add maven dependencies
<dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-spring</artifactId> <version>1.17.1</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> </exclusions> </dependency>Use SpringServlet for jersey-servlet in
web.xml<servlet> <servlet-name>jersey-servlet</servlet-name> <servlet-class> com.sun.jersey.spi.spring.container.servlet.SpringServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
添加maven依赖
<dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-spring</artifactId> <version>1.17.1</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> </exclusions> </dependency>在 jersey-servlet 中使用 SpringServlet
web.xml<servlet> <servlet-name>jersey-servlet</servlet-name> <servlet-class> com.sun.jersey.spi.spring.container.servlet.SpringServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
Now the @Autowired works properly and the object is not null anymore.
现在@Autowired 工作正常,对象不再为空。
I'm a little bit confused about the exclusions I have to use in maven when using jersey-spring dependency, but that's another issue :)
我对使用 jersey-spring 依赖项时必须在 maven 中使用的排除项有点困惑,但这是另一个问题:)
Thank you!
谢谢!
回答by Nikita Bosik
Integration Spring with Jersey 2(org.glassfish.*):
将 Spring 与Jersey 2( org.glassfish.*)集成:
Maven
马文
Some dependencies may be unnecessary, please check & clear it after things got working.
某些依赖项可能是不必要的,请在一切正常后检查并清除它。
<properties>
<jersey.version>2.5</jersey.version>
</properties>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<!-- if your container implements Servlet API older than 3.0, use "jersey-container-servlet-core" -->
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<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>
web.xml
网页.xml
<servlet>
<servlet-name>my-rest-service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package.with.rest.services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-rest-service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
应用上下文.xml
During the Spring upgrading I had to move it from /main/webapp/WEB-INF/to /main/resources/(details).
在 Spring 升级期间,我不得不将它从 移动/main/webapp/WEB-INF/到/main/resources/(详细信息)。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="my.package.with.rest.services" />
</beans>
Example REST service
示例 REST 服务
public interface MyService
{
String work(String s);
}
...
@Service
public class MyServiceImpl implements MyService
{
@Override
public String work(String s)
{
return "Hello, " + s;
}
}
...
@Path("demo/")
@Component
public class DemoRestService
{
@Autowired
private MyService service;
@GET
@Path("test")
public Response test(@FormParam("param") String par)
{
try
{
String entity = service.work(par);
return Response.ok(entity).build();
}
catch (Exception e)
{
e.printStackTrace();
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Epic REST Failure").build();
}
}
}
回答by chengl
or you can simply extend SpringBeanAutoWiringSupport class. Like this: public class DemoRestService extends SpringBeanAutoWiringSupport. By extending this support class, properties of your service class can be auto-wired.
或者您可以简单地扩展 SpringBeanAutoWiringSupport 类。像这样:public class DemoRestService extends SpringBeanAutoWiringSupport。通过扩展这个支持类,您的服务类的属性可以自动连接。
回答by Vilmantas Baranauskas
Another possible option is to manually invoke autowiring in your jersey resource:
另一种可能的选择是在您的球衣资源中手动调用自动装配:
@Context
private ServletContext servletContext;
@PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}
Hmm, you get a "manual autowiring"...
嗯,你会得到一个“手动自动装配”......

