Spring DI - REST 服务中的自动装配属性为空 [英] Spring DI - Autowired property is null in a REST service

查看:19
本文介绍了Spring DI - REST 服务中的自动装配属性为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开始使用 Spring DI,但我在依赖注入方面苦苦挣扎,更糟糕的是,我什至不确定为什么,因为对我来说似乎没问题.希望大家帮帮我!

问题是注释为 @Autowired 的属性总是 null

我有几个使用 Maven 结构的项目:

  • com.diegotutor.lessondeliver
  • com.diegotutor.utility

我在 Tomcat 7 上运行示例

我在我的 pom.xml 中使用以下依赖项:

  • 弹簧上下文 3.2.4
  • spring-web 3.2.4
  • 球衣服务器 1.17.1
  • 球衣核心 1.17.1
  • 球衣小服务程序 1.17.1

简单的想法是拥有一个 RESTful 服务,通过依赖注入能够打印出位于以下位置的配置文件中的属性值:D:configuracion.conf.>

com.diegotutor.utility 我有以下界面:

package com.diegotutor.utility;公共接口配置服务{public String getProperty(final String propertyName);}

实施者:

package com.diegotutor.utility.impl;导入 java.io.FileInputStream;导入 java.io.IOException;导入 java.io.InputStream;导入 java.io.Reader;导入 java.util.Properties;导入 com.diegotutor.utility.ConfigService;公共类 PropertyFileConfigService 实现了 ConfigService{属性道具;公共 PropertyFileConfigService(最终 InputStream 输入)抛出 IOException {如果(输入==空){throw new IllegalArgumentException("输入流不能为空");}prop = 新属性();prop.load(输入);}公共 PropertyFileConfigService(最终字符串文件名)抛出 IOException {最终 FileInputStream input = new FileInputStream(fileName);prop = 新属性();prop.load(输入);}公共 PropertyFileConfigService(最终读者输入)抛出 IOException {prop = 新属性();prop.load(输入);}public String getProperty(final String propertyName) {返回 prop.getProperty(propertyName);}}

com.diegotutor.lessondeliver 我有 RESTful 服务,我想在其中使用 ConfigService 的注入实例:

package com.diegotutor.lessondeliver;导入 javax.ws.rs.GET;导入 javax.ws.rs.Path;导入 javax.ws.rs.Produces;导入 javax.ws.rs.core.MediaType;导入 org.apache.commons.logging.Log;导入 org.apache.commons.logging.LogFactory;导入 org.springframework.beans.factory.annotation.Autowired;导入 org.springframework.stereotype.Component;导入 com.diegotutor.utility.ConfigService;@小路("/")@成分公共类 HelloWorld {私有静态最终日志日志 = LogFactory.getLog(HelloWorld.class);@自动连线私有配置服务配置服务;@Path("/helloworld")@得到@Produces(MediaType.TEXT_PLAIN)公共字符串 getHello() {String host = configService.getProperty("host");return "Hello World! HOST" + 主机;//configService 为空!!//所以它在调用 getProperty 时抛出一个空指针异常}}

最后在 /com.diegotutor.lessondeliver/src/main/webapp/WEB-INF/service-beans.xml 我有以下 XML 应用程序上下文文件,我在其中使用了 ConfigService (PropertyFileConfigService) 在其上注入配置文件读取的路径:

<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"/></豆类>

显然我已经在这个 com.diegotutor.lessondeliver 网络应用程序的 web.xml 中指定了我想要的 service-beans.xml作为ConfigLocation和一个监听器ContextLoaderListener,RESTful服务依赖ServletContainer

如果我按照建议指定 context:component-scan 在 com.diegotutor 中查找组件 此处 并且我强制通过 Spring 创建对象,方法是不使用任何建议的新语句 此处为什么我将带注释的 configService 设为 null?为什么 Spring 无法注入 com.diegotutor.utility.impl.PropertyFileConfigService 的实例?

任何帮助将不胜感激!

谢谢

根据要求,我的 web.xml 如下:

<display-name>com.diegotutor.lessondeliver</display-name><上下文参数><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/service-beans.xml</param-value></context-param><听众><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></监听器><小服务程序><servlet-name>球衣-servlet</servlet-name><servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class><启动时加载>1</启动时加载></servlet><servlet-mapping><servlet-name>球衣-servlet</servlet-name><url-pattern>/rest/*</url-pattern></servlet-mapping></web-app>

解决方案

你说得对!问题似乎是 Jersey 完全不知道 Spring 并实例化了自己的对象.为了让 Jersey 了解 Spring 对象的创建(通过依赖注入),我必须集成 Spring + Jersey.

集成:

  1. 添加 maven 依赖

    <依赖><groupId>com.sun.jersey.contribs</groupId><artifactId>球衣弹簧</artifactId><version>1.17.1</version><排除事项><排除><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></排除><排除><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></排除><排除><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></排除><排除><groupId>org.springframework</groupId><artifactId>spring-web</artifactId></排除></排除项></依赖>

  2. web.xml

    中为 jersey-servlet 使用 SpringServlet

    <servlet-name>球衣-servlet</servlet-name><servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class><启动时加载>1</启动时加载></servlet>

现在@Autowired 工作正常,对象不再为空.

我对使用 jersey-spring 依赖项时必须在 maven 中使用的排除有点困惑,但这是另一个问题:)

谢谢!

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!

The problem is that a property annotated as @Autowired is always null

I've got a few projects with Maven structure:

  • com.diegotutor.lessondeliver
  • com.diegotutor.utility

I'm running the examples over Tomcat 7

I'm using the following dependencies in my 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

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.

At com.diegotutor.utility I have the following interface:

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.lessondeliver I have the RESTful service where I would like to use an injected instance of the 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.xml I 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:

<?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.xml of this com.diegotutor.lessondeliver web app that I want service-beans.xml as ConfigLocation and a listener ContextLoaderListener, and the RESTful service relies on ServletContainer

If I'm specifying context:component-scan to look for Components in com.diegotutor as suggested here and 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?

Any help will be much appreciated!

Thank you

EDITED:

As requested, my web.xml is as follows:

<?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>

解决方案

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.

To integrate:

  1. 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>
    

  2. 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>
    

Now the @Autowired works properly and the object is not null anymore.

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 :)

Thank you!

这篇关于Spring DI - REST 服务中的自动装配属性为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆