JPA:NoSuchBeanDefinitionException:没有定义名为 'myPU' 的 bean

JPA: NoSuchBeanDefinitionException: No bean named 'myPU' is defined

我正在将我们的网络应用程序从基于 XML 的 IoC、直接的 Hibernate 网络应用程序转换为使用注释和 JPA 2.1 的网络应用程序。我们的应用程序服务器是 WebLogic 12.1.3,我们使用 Spring 3.2.13 和 Hibernate 4.3.9。我们的架构是分层的,每一层都以其自己的 JAR 文件结尾。 EAR文件的布局如下:

|-EAR
   |-- my-app.ear
   |-- my-app.war
   |-- lib
        |-- my-web.jar
        |-- my-services.jar
        |-- my-jpa.jar
        |   |-- META-INF
        |       |-- persistence.xml
        |-- someotherlib.jar

在 IoC 链的顶端是我们的 DelegateFactory,它被 Struts1 动作使用(我们稍后会升级它)。

@Configuration
@ComponentScan({"com.mycompany.myapp.dao.jpa"})
public class DelegateFactory
{
  public static DelegateFactory getInstance()
  {
    if (singleton == null)
    {
      AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

      ctx.register(DelegateFactory.class);
      ctx.refresh();

      singleton = ctx.getBean(DelegateFactory.class);

      ctx.close();
    }
    return singleton;
  }
}

IoC 在查找 Web、服务和 DAO bean 时有效,但在尝试查找持久性单元时失败。下面是我们的 JPA DAO 的基础 class。它是一个普通的 DAO,而不是 Spring DAO。为了使其工作,我尝试同时注入 em 和 emf。

public abstract class AbstractMyProjectJpaDao extends AbstractJpaTypedDao
{
  public static final String PERSISTENCE_UNIT_NAME = "myPU";

  @PersistenceUnit(unitName = PERSISTENCE_UNIT_NAME, name = PERSISTENCE_UNIT_NAME)
  @Override
  public void setEntityManagerFactory(
    EntityManagerFactory emf)
  {
    super.setEntityManagerFactory(emf);
  }

  @PersistenceContext(unitName = PERSISTENCE_UNIT_NAME, name = PERSISTENCE_UNIT_NAME, type = PersistenceContextType.TRANSACTION)
  @Override
  public void setEm(
    EntityManager em)
  {
    super.setEm(em);
  }
}

到目前为止,我们似乎唯一需要的 XML 文件是下面的 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="myPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>java:/jdbc/myDS</jta-data-source>
    (declaration of persistent entities here)
  </persistence-unit>
</persistence>

这是失败的原因:

Caused By: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myPU' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:575)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.orm.jpa.EntityManagerFactoryUtils.findEntityManagerFactory(EntityManagerFactoryUtils.java:110)

我的猜测是它找不到 persistence.xml 文件,但根据我的阅读,它在一个有效的位置。

我错过了什么?

尝试创建 PersistenceConfiguration。 repo.package 指向您可能使用的任何存储库位置,例如 Springs CRUD/JPA 存储库。 entity.package 指向您的 JPA DAO 所在的包。

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    basePackages = {"repo.package"},
    entityManagerFactoryRef = "entityManagerFactory",
    transactionManagerRef = "transactionManager"
)
public class PersistenceConfiguration {

  public static final HashSet<String> cacheNames = new HashSet<>();

  private static final String[] PACKAGES_TO_SCAN = {"entities.package"};

  private static final Properties hibernateProperties;
  static {
    hibernateProperties = new Properties();
    hibernateProperties.setProperty("hibernate.connection.zeroDateTimeBehavior", "convertToNull");
    hibernateProperties.setProperty("hibernate.dbcp.maxActive", "50");
    hibernateProperties.setProperty("hibernate.dbcp.maxIdle", "10");
    hibernateProperties.setProperty("hibernate.dbcp.maxWait", "5000");
    hibernateProperties.setProperty("hibernate.jdbc.batch_size property", "50");
    hibernateProperties.setProperty("hibernate.connection.charSet", "UTF-8");
    hibernateProperties.setProperty("hibernate.connection.characterEncoding", "UTF-8");
    hibernateProperties.setProperty("hibernate.connection.useUnicode", "true");
  }

   @Bean
   public DataSource dataSource(){
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName("database.driver");
      dataSource.setUrl("database url");
      dataSource.setUsername( "tutorialuser" );
      dataSource.setPassword( "tutorialmy5ql" );
      return dataSource;
   }

  /**
   * Create the entity manager factory bean used in the database connection
   * @return entityManagerFactoryBean
   */
  @Primary
  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
    lef.setDataSource(dataSource);
    lef.setJpaVendorAdapter(portalJpaVendorAdapter());
    lef.setPackagesToScan(PACKAGES_TO_SCAN);
    lef.setJpaProperties(hibernateProperties);
    lef.setPersistenceUnitName("my_pu");
    return lef;
  }

  /**
   * Create the session factory bean
   * @return sessionFactoryBean
   */
  @Bean
  public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean sessionBean = new LocalSessionFactoryBean();
    sessionBean.setDataSource(dataSource);
    sessionBean.setPackagesToScan(PACKAGES_TO_SCAN);
    sessionBean.setHibernateProperties(hibernateProperties);
    return sessionBean;
  }

  /**
   * Create the JPA Vendor adaptor bean that is used in the entity manager factory
   * @return jpaVendorAdaptor
   */
  @Primary
  @Bean
  public JpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setShowSql(false);
    hibernateJpaVendorAdapter.setGenerateDdl(false);
    hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
    return hibernateJpaVendorAdapter;
  }

  /**
   * Create the transaction manager bean 
   * @return transactionManager
   */
  @Primary
  @Bean
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(portalEntityManagerFactory().getObject());
    return new JpaTransactionManager();
  }
}

如果您已经创建了数据源 bean,则可以自动装配它而不是直接创建 bean。

问题的第一部分是我没有插入 EntityManagerFactory。我最终创建了一个 dao-beans.xml 文件:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myPU" />
</bean>

然后我必须将 @ImportResource 注释添加到我的 DelegateFactory 以便可以找到 XML 文件。

@Configuration
@ComponentScan({"com.mycompany.myapp.dao.jpa"})
@ImportResource("classpath:dao-beans.xml")
public class DelegateFactory
{
...
}

我还必须将 persistence.xml 中数据源的 JNDI 名称从 "java:/jdbc/myDS" 更改为 "jdbc/myDS"。我认为这是 WebLogic 的事情。