JPA EntityManager没有注入Spring 4

时间:2015-03-02 13:11:43

标签: java dependency-injection entitymanager spring-4

在完成了几次与guice的合作之后,我尝试使用注释在当前版本中重新演绎spring框架。但是,我似乎无法在测试期间使用EntityManager注释弹出@PersistenceContext。这是我的设置:

的persistence.xml

<persistence 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
    <persistence-unit name="com.whatever.shop.database" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.whatever.shop.domain.Product</class>
        <class>com.whatever.shop.domain.Order</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
            <property name="javax.persistence.jdbc.url"     value="jdbc:hsqldb:mem:testdb" />
            <property name="javax.persistence.jdbc.user" value="sa" />
            <property name="javax.persistence.jdbc.password" value="" />
            <property name="hibernate.dialect"     value="org.hibernate.dialect.HSQLDialect" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
</persistence-unit>
</persistence>

具有持久化上下文的通用DAO实现

public abstract class GenericDAOImpl<T, PK extends Serializable> implements GenericDAO<T, PK> {

  @PersistenceContext(unitName="com.whatever.shop.database")
  private EntityManager entityManager;

  private Class<T> entityType;

  public GenericDAOImpl(Class<T> entityType) {
    this.entityType = entityType;
  }

  @Override
  public T getById(PK id) {
    return entityManager.find(entityType, id);
  }

  // Some more methods
}

ProductDAOImpl

@Repository
public class ProductDAOImpl extends GenericDAOImpl<Product, Long> implements ProductDAO {

  @PersistenceContext(unitName="com.whatever.shop.database")
  private EntityManager entityManager;

  public ProductDAOImpl() {
    super(Product.class);
  }
}

BeanConfig类,用于类定义的bean定义:

package com.whatever.shop.database;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.whatever.shop.database.jpa"})
public class BeanConfig {

  @Bean
  public EntityManagerFactory entityManagerFactory() {
    return Persistence.createEntityManagerFactory("com.whatever.shop.database");
  }

  @Bean
  public EntityManager entityManager() {
    return entityManagerFactory().createEntityManager();
  }
}

最后,测试类我尝试注入:

package com.whatever.shop.database.jpa;

import static org.junit.Assert.fail;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.whatever.shop.database.BeanConfig;
import com.whatever.shop.domain.Product;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={BeanConfig.class})
public class ProductDAOTest {

  @Autowired
  private ProductDAO productDao;

  /**
   * Test method for {@link com.whatever.shop.database.GenericDAOImpl#getById(java.lang.Object)}.
   */
  @Test
  public void testGetById() {
    productDao.save(new Product());
  }
}

我对这应该如何运作的理解如下

  1. 测试运行器查看Application上下文bean并创建EntityManagerFactory
  2. @ComponentScan注释应遍历我的所有DAO实现,检测@Repository注释并执行PersistenceAnnotationBeanPostProcessor类型位和bob。
  3. 但是每当我运行测试时,NullPointerException都会得到EntityManager。 bean正在被实例化,但它没有连接到DAO。

1 个答案:

答案 0 :(得分:0)

解决: 这里的问题是我试图像EntityManager那样对待SessionFactory。 Spring需要自己的工厂对象才能出现在上下文中,因此它知道在遇到@PersistenceContext注释时要做什么。更改位于BeanConfig类中。

@Configuration
@ComponentScan(basePackages = {"com.whatever.shop.database.jpa"})
public class BeanConfig {

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
      LocalContainerEntityManagerFactoryBean thing = new LocalContainerEntityManagerFactoryBean();
      thing.setPersistenceUnitName("com.whatever.shop.database");
      return thing;
  }

  @Bean
  public JpaTransactionManager transactionManager() {
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(entityManagerFactory().nativeEntityManagerFactory);
      return transactionManager;
  } 
}