Spring @Autowired在@Repository bean中给出null

时间:2014-04-10 14:34:28

标签: java spring

我有一个使用@Autowired注入SessionFactory的简单独立应用程序,这里是代码:

package au.edu.rdsi.rexportal;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

@Repository("rexportalConsole")
public class RexportalConsole {
    @Autowired
    private SessionFactory sessionFactory;

    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.getEnvironment().setActiveProfiles("development");
        ctx.load("classpath:META-INF/spring-rexportal.xml");
        ctx.refresh();
        RexportalConsole rc = (RexportalConsole) ctx.getBean("rexportalConsole");
        System.out.println(rc);
        System.out.println(rc.sessionFactory);
    }

}

当我运行这个程序时,我总是为sessionFactory属性获取null:

au.edu.rdsi.rexportal.RexportalConsole@1f3a1de9
null

但如果我将@Repository更改为@Component,我会得到正确的结果,并且我可以使用sessionFactory bean:

au.edu.rdsi.rexportal.RexportalConsole@14eb7ad0
org.hibernate.impl.SessionFactoryImpl@6fcbf86a

我想使用@Repository,因为我需要翻译异常,你可以在我的application.xml中看到,PersistenceExceptionTranslationPostProcessor适用于@Respository:

<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee  http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

<context:component-scan base-package="au.edu.rdsi.rexportal" />

<context:annotation-config />

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />

<beans profile="production, qa, staging">
    <jee:jndi-lookup id="rexportalDS" jndi-name="java:jboss/datasources/rexportalDS" />
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="rexportalDS" />
        <property name="mappingLocations" value="classpath:au/edu/rdsi/rexportal/domain/**/*.hbm.xml" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
            </props>
        </property>
    </bean>
</beans>

<beans profile="development, test">
    <bean id="rexportalDS" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://localhost:5432/rexportal" />
        <property name="username" value="password" />
        <property name="password" value="password" />
        <property name="initialSize" value="5" />
        <property name="maxActive" value="10" />
    </bean>
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="rexportalDS" />
        <property name="mappingLocations" value="classpath:au/edu/rdsi/rexportal/domain/**/*.hbm.xml" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true"</prop>
            </props>
        </property>
    </bean>
</beans>

我错过了什么吗?为什么@Component在这里工作但是@Respository?

这是我使用@Repository时的日志:

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [META-INF/spring-rexportal.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@6f3a342a: startup date [Sun Apr 13 00:31:30 EST 2014]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.context.support.GenericXmlApplicationContext - Bean 'rexportalDS' of type [class org.apache.commons.dbcp.BasicDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO : org.springframework.context.support.GenericXmlApplicationContext - Bean 'sessionFactory' of type [class org.springframework.orm.hibernate3.LocalSessionFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@37cae761: defining beans [messageDao,rexportalConsole,messageService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,rexportalDS,sessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
au.edu.rdsi.rexportal.RexportalConsole@3a3248be
null
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@6f3a342a: startup date [Sun Apr 13 00:31:30 EST 2014]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@37cae761: defining beans [messageDao,rexportalConsole,messageService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,rexportalDS,sessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

当我使用@Component时记录:

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [META-INF/spring-rexportal.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@2c683bfc: startup date [Sun Apr 13 00:42:43 EST 2014]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.context.support.GenericXmlApplicationContext - Bean 'rexportalDS' of type [class org.apache.commons.dbcp.BasicDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO : org.springframework.context.support.GenericXmlApplicationContext - Bean 'sessionFactory' of type [class org.springframework.orm.hibernate3.LocalSessionFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3d600a0c: defining beans [messageDao,rexportalConsole,messageService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,rexportalDS,sessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
au.edu.rdsi.rexportal.RexportalConsole@26d6221b
org.hibernate.impl.SessionFactoryImpl@34592e88
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@2c683bfc: startup date [Sun Apr 13 00:42:43 EST 2014]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3d600a0c: defining beans [messageDao,rexportalConsole,messageService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,rexportalDS,sessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

2 个答案:

答案 0 :(得分:2)

当异常转换代理包装rexportalConsole bean时,该字段访问正在中断。否则@Autowired将会合适。

看看这个

@Component
//@Repository
public class RexportalConsole {
    @Autowired
    private SessionFactory sessionFactory;

    @PostConstruct
    public void foo() {
        System.out.println("postconstruct this:" + this);
        System.out.println("postconstruct this.sessionFactory:" + this.sessionFactory);
    }

    public static void main(String[] args) throws InterruptedException {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.getEnvironment().setActiveProfiles("development");
        ctx.load("classpath:META-INF/spring-rexportal.xml");
        ctx.refresh();
        RexportalConsole rc = (RexportalConsole) ctx.getBean("rexportalConsole");
        System.out.println("main rc:" + rc);
        System.out.println("main rc.sessionFactory:" + rc.sessionFactory);
        System.out.println("main rc.getSessionFactory():" + rc.getSessionFactory());
        // rc.fail();
    }


    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }


    public void fail() {
        throw new SQLGrammarException("foo",null);
    }
}

产生

postconstruct this:au.edu.rdsi.rexportal.RexportalConsole@7e3e1a61
postconstruct this.sessionFactory:org.hibernate.impl.SessionFactoryImpl@1f361707
main rc:au.edu.rdsi.rexportal.RexportalConsole@7e3e1a61
main rc.sessionFactory:org.hibernate.impl.SessionFactoryImpl@1f361707
main rc.getSessionFactory():org.hibernate.impl.SessionFactoryImpl@1f361707

交换注释以使用@Repository会产生此

postconstruct this:au.edu.rdsi.rexportal.RexportalConsole@79e893ae
postconstruct this.sessionFactory:org.hibernate.impl.SessionFactoryImpl@1437c309
main rc:au.edu.rdsi.rexportal.RexportalConsole@79e893ae
main rc.sessionFactory:null
main rc.getSessionFactory():org.hibernate.impl.SessionFactoryImpl@1437c309

可能有一些超级显而易见的东西我不知道为什么会发生这种情况,例如代理代理getter方法并且只是在直接字段访问时返回null,但我有挖掘以找出原因。

无论如何,您的布线确实有效。

更新 :另一个答案表明PersistenceExceptionTranslationPostProcessor是多余的。事实并非如此。如果您取消注释上面代码中的rc.fail()行,则在注释掉SQLGrammarException bean时会看到一个Hibernate PostProcessor,当你包含它时会看到一个Spring InvalidDataAccessResourceUsageException。只有在声明@Repository时才会创建包装PostProcessor并执行异常转换的代理。它可能是通过隐藏字段来破坏字段访问的代理。您可以在第14.2.2节的manual中阅读相关内容。

答案 1 :(得分:-3)

尝试自动装配会话工厂,如下所示:

private SessionFactory sessionFactory;

@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
}