【问题标题】:Spring @Autowired OK on JUnit, NPE on main classJUnit上的Spring @Autowired OK,主类上的NPE
【发布时间】:2012-04-10 13:14:29
【问题描述】:

我在this github 上托管了一个开源项目。我正面临一个奇怪的情况。我发现很多人可以让 @Autowired Spring 注释在他们的主类上工作,但不能在他们的 JUnit 测试类上工作。我的问题是相反的。我可以在我的 JUnit 测试类中成功使用 @Autowired,但是当测试调用我的主类时,依赖项不会在那里注入。这是我的上下文(简化版):

登录类:

package net.openrally.restaurant.core.exposure.resource;

@Path("/login")
@Component
@Transactional
@Singleton
@Produces("application/json")
@Consumes("application/json")
public class Login extends BaseResource{

    @Autowired
    private UserDAO userDAO;

    @POST
    public Response post(String requestBody){

        ...

        //NullPointerException
        User user = userDAO.loadByCompanyIdAndLogin(companyId, login);
    }

    ...

}

LoginTest 类:

package net.openrally.restaurant.core.exposure.resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class LoginTest extends BaseResourceTest {

    @Autowired
    private UserDAO userDAO;

    ...

    @Test
    public void testInvalidPassword() {

    ....

    // Works perfectly!
    userDAO.save(user);

    ....

    }

}

applicationContext.xml:

<?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-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:configuration.properties</value>
            </list>
        </property>
    </bean>

    <context:annotation-config />
    <context:component-scan base-package="net.openrally.restaurant.core" />

    <import resource="db-config.xml" />
</beans>

我这几天一直在寻找解决方案。到目前为止我能找到的,大多数有@Autowired 问题的人在他们的spring xml 中没有&lt;context:annotation-config /&gt;xmlns:context="http://www.springframework.org/schema/context",或者在他们希望DI 发生的类中没有@Component 家庭注释,正如您所看到的,它们都在那里 :(。我的项目中只有一个 applicationContext.xml 适合运行时和测试(我有不同的 configuration.properties 来设置不同的数据库凭据和日志级别,但没有 spring那里的配置)

我正在使用:

Spring: 3.1.0.RELEASE
JUnit: 4.10
Jersey: 1.11
CLIB: 2.2.2

任何想法,我的意思是任何 :),都非常感谢。

更新

运行测试时出现以下日志:

2012-03-27 07:37:02,457 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'login'
2012-03-27 07:37:02,457 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'login'
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Found injected element on class [net.openrally.restaurant.core.exposure.resource.Login]: AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.ConfigurationDAO net.openrally.restaurant.core.exposure.resource.Login.configurationDAO
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Found injected element on class [net.openrally.restaurant.core.exposure.resource.Login]: AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.UserDAO net.openrally.restaurant.core.exposure.resource.Login.userDAO
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Eagerly caching bean 'login' to allow for resolving potential circular references
2012-03-27 07:37:02,459 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Getting BeanInfo for class [net.openrally.restaurant.core.exposure.resource.Login]
2012-03-27 07:37:02,462 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Caching PropertyDescriptors for class [net.openrally.restaurant.core.exposure.resource.Login]
2012-03-27 07:37:02,462 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Found bean property 'class' of type [java.lang.Class]
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'login': AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.ConfigurationDAO net.openrally.restaurant.core.exposure.resource.Login.configurationDAO
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'configurationDAO'
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'login' to bean named 'configurationDAO'
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'login': AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.UserDAO net.openrally.restaurant.core.exposure.resource.Login.userDAO
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDAO'
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'login' to bean named 'userDAO'
2012-03-27 07:37:02,464 DEBUG [main] org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator - Creating implicit proxy for bean 'login' with 0 common interceptors and 1 specific interceptors
2012-03-27 07:37:02,464 DEBUG [main] org.springframework.aop.framework.Cglib2AopProxy - Creating CGLIB2 proxy: target source is SingletonTargetSource for target object [net.openrally.restaurant.core.exposure.resource.Login@60532a0a]
2012-03-27 07:37:02,465 DEBUG [main] org.springframework.aop.framework.Cglib2AopProxy - Unable to apply any optimisations to advised method: public javax.ws.rs.core.Response net.openrally.restaurant.core.exposure.resource.Login.post(java.lang.String)

Spring 是否可以正确创建我的 bean,但 Jersey 使用它自己的非自动装配实例?

【问题讨论】:

  • 您的 bean 上的 @Component@Singleton 之间是否存在任何冲突?以及如何加载您的 applicationContext.xml 文件以供运行时使用?
  • 您好 nico_ekito,感谢您的意见。 @Singleton 只是一种优化。在您发表评论后,我尝试将其删除,但没有运气...appliationContext.xml 位于资源文件夹中,并且项目具有由 maven 控制的 spring 依赖项。我计划使用 jetty 作为 Web 容器,但对于测试我使用 Jersey 的 Grizzly Web Container。
  • 但是您的applicationContext.xml 文件是如何加载到您的运行时应用程序中的呢?通过ClassPathXmlApplicationContext ?通过网络应用程序?
  • 目前。我的 applicationContext.xml 由 junit 测试引导加载。对于生产,它将由 Web 容器加载。我没有得到太多关于那个的细节......我怎么能检查它是否被正确加载?看起来似乎表明......
  • 如果不使用任何上下文加载器,它将不会加载。在 Web 应用程序中,使用 ContextLoaderListener : static.springsource.org/spring/docs/2.5.x/reference/…

标签: spring junit autowired


【解决方案1】:

研究了一段时间,没找到让GrizzlyWeb使用spring加载的上下文的方法,于是尝试寻找替代方案。

然后我找到了Hifaces20,它可以让你在同一个 JVM 中启动和停止一个 jetty 实例(这意味着你可以使用一个内存数据库,你的测试和应用程序都可以看到)

【讨论】:

    【解决方案2】:

    我遇到了完全相同的问题,后来发现是开发人员问题:)

    我正在创建一个新对象,而不是使用 spring bean。

    假设 class MyService 自动装配一个 dao 类 MyDao myDaoBean。现在假设我想在MyController 中使用MyService,我应该在Spring bean myServiceSpringBean 中连接。如果我尝试创建一个新的 myServiceObject,那么 Spring 不会将 myDaoBean 连接到 myServiceObject,因为它不知道该新服务对象。

    这导致myDaoBean 为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-22
      • 2011-09-28
      • 1970-01-01
      • 2012-03-30
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      相关资源
      最近更新 更多