私はSpring DIを使い始めていますが、依存関係の注入に苦労しています。さらに悪いのは、理由がよく分からないためです。うまくいけば、皆さんが私を助けることができます!
問題は、@ Autowiredと注釈が付けられたプロパティが常にnull
Maven構造のプロジェクトがいくつかあります。
Tomcat 7でサンプルを実行しています
_pom.xml
_で次の依存関係を使用しています。
単純なアイデアは、依存性注入を介して、次の場所にある構成ファイルにあるプロパティの値を出力できるRESTfulサービスを提供することです:_D:\configuracion.conf.
_
com.diegotutor.utilityに次のインターフェイスがあります:
_package com.diegotutor.utility;
public interface ConfigService {
public String getProperty(final String propertyName);
}
_
実装者:
_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);
}
}
_
そして、com.diegotutor.lessondeliverに、ConfigServiceの挿入されたインスタンスを使用するRESTfulサービスがあります。
_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
}
}
_
最後に_/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>
_
明らかに、この_web.xml
_ Webアプリの_com.diegotutor.lessondeliver
_で、ConfigLocationおよびリスナーContextLoaderListener
として_service-beans.xml
_を指定し、RESTfulにしましたサービスはServletContainerに依存しています
Context:component-scanを指定して_com.diegotutor
_でコンポーネントを検索するように提案している場合 here 提案されているように新しいステートメントを使用せずにSpringでオブジェクトの作成を強制している場合 ここ 、注釈付きのconfigServiceがnullとして取得されるのはなぜですか? Springが_com.diegotutor.utility.impl.PropertyFileConfigService
_のインスタンスを注入できないのはなぜですか?
どんな助けでも大歓迎です!
ありがとうございました
編集:
要求どおり、私の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>
_
あなたは正しかった!問題は、ジャージーが完全にSpringを認識せず、独自のオブジェクトをインスタンス化することです。 Jerseyに(依存関係注入による)Springオブジェクトの作成を認識させるために、Spring + Jerseyを統合する必要がありました。
統合するために:
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>
web.xml
のjersey-servletにSpringServletを使用します
<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>
これで、@ Autowiredは正しく機能し、オブジェクトはnullではなくなりました。
ジャージースプリングの依存関係を使用するときにmavenで使用する必要がある除外について少し混乱していますが、それは別の問題です:)
ありがとうございました!
Jersey 2との統合Spring(org.glassfish.*
):
一部の依存関係は不要な場合があります。正常に動作した後で確認してクリアしてください。
<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>
<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>
春のアップグレードの間、私はそれを/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>
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();
}
}
}
または、単にSpringBeanAutoWiringSupportクラスを拡張することもできます。このような: public class DemoRestService extends SpringBeanAutoWiringSupport
。このサポートクラスを拡張することにより、サービスクラスのプロパティを自動配線できます。
別の可能なオプションは、ジャージーリソースで自動配線を手動で呼び出すことです。
@Context
private ServletContext servletContext;
@PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}
うーん、あなたは「手動自動配線」を取得します...