@Autowired @Entity内部无法正常工作

时间:2016-01-24 19:59:32

标签: java spring autowired

当我登录我的应用程序时,我会在NullPointerException字段@Autowired获得hashProvider。奇怪的是,它有时只会发生!当我尝试调试模式时,该字段是自动装配的,当我正常运行时,它不是。

@Configurable(preConstruction=true)
@Entity
@Table(name="DB_USER")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "USER_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class User extends AbstractEntity {

     //...

    @Autowired(required = true)
    private transient HashProvider hashProvider; 

     //...

    public boolean hasPassword(String password){
        LOG.info("is null "+(hashProvider==null));   //sometimes is null sometimes not
        return hashProvider.computeHash(password + salt).equals(this.password);  //null pointer
    }
}

@Component("hashProvider")
public class SHA1Provider implements HashProvider{
    //...
    @Override
    public String computeHash(String s) {
        //...
    }
}

另外,以不同用户身份登录会抛出异常。以Doctor身份登录时,该字段为空,为AdminUser,该字段不是

@Entity
public class AdminUser extends User {

    @Override
    public String toString() {
        return super.toString() + "AdminUser{" + '}';
    }

    @Override
    public Boolean isAdmin() {
        return true;
    }    
}

@Entity
@DiscriminatorValue("doctor")
public class Doctor extends User {

    private String address;

    @Column(length = 10, unique = true, name = "DOCTOR_BCN", nullable = false)
    private Long birthNumber;

    private Integer phone;

    @OneToMany(mappedBy = "doctor")
    @OrderBy("name ASC")
    private List<Patient> patients;

    //setters and getters       

    @Override
    public String toString() {
        return super.toString() + "Doctor{}";
    }

    @Override
    public Boolean isAdmin() {
        return false;
    }
}

这是applicationContext.xml文件:

<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:mvc="http://www.springframework.org/schema/mvc"
       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
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"
        >
    <!-- Use annotation to configure Spring context -->
    <context:annotation-config />
    <mvc:annotation-driven />
    <!-- Search for beans under the com.wpa package (Using annotation @Component, @Repository, @Service) -->
    <context:component-scan base-package="com.wpa"/>
    <!-- @Configurable support -->
    <context:spring-configured/>
    <!-- Property files -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/properties/jdbc.properties</value>
                <value>/WEB-INF/properties/jpa.properties</value>
            </list>
        </property>
    </bean>
    <!-- Connection pool -->
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClassName}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- This defines the EntityManagerFactory bean, which provides the application with EntityManager instances = persistence context -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
                <property name="databasePlatform" value="${jpa.platform}"/>
                <property name="generateDdl" value="true"/>
                <property name="showSql" value="true"/>
            </bean> 
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="eclipselink.weaving" value="static"/>
                <entry key="eclipselink.ddl-generation" value="create-or-extend-tables" />
            </map>
        </property>
        <property name="packagesToScan" value="com.wpa"/>
        <property name="jtaDataSource" ref="dataSource"/>
    </bean>

    <!-- Transaction manager for declarative transactional demarcation -->
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- Use the declared transaction manager to manage transaction using the @Transactional annotation -->
    <!-- proxy-target-class=true enables use of concrete classes without interfaces as beans with the @Transactional annotation -->
    <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager">
            <ref bean="txManager"/>
        </property>
    </bean>   
</beans>

1 个答案:

答案 0 :(得分:0)

@Autowire只能用于由spring标记的类。例如@Service, @component ,@Repostitory

编辑:我错过了@Configurable,这使得它也成为了一个春天。

我知道的另一件事是,如果你在反序列化后在成员上写瞬态它将为null ..这似乎与你的情况非常相似。 这有意义吗?

编辑: 不应在JPA实体中使用Spring bean。这是不好的做法。 实现此目的的最佳实践是创建包装器,其中包含具有附加功能的pojo。我认为最好的办法就是让逻辑服务即使它是一个很小的逻辑......