Spring 3.1 + Hibernate 4.1 JPA, менеджер сущностей factory зарегистрирован дважды

Я использую Spring Framework 3.1 с Hibernate 4.1 в качестве поставщика JPA, и у меня есть полностью функциональная настройка, но каждый раз, когда веб-приложение запускается, я вижу это предупреждающее сообщение:

14:28:12,725  WARN pool-2-thread-12 internal.EntityManagerFactoryRegistry:80 - HHH000436: Entity manager factory name (something) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

Приложение отлично работает, но предупреждающие сообщения, подобные мне, и часы поиска, настройки и экспериментирования ни к чему не привели. Я пробовал изменить имя factory и добавлять и исключать куски конфигурации, все безрезультатно. Похоже, что что-то в Spring или Hibernate просто дважды инициализирует диспетчер сущностей factory.

FYI, я использую функции packageToScan для LocalContainerEntityManagerFactoryBean для настройки диспетчера сущностей без файла persistence.xml.

Я сжал свой XML-контекст Spring следующим образом, и проблема не устранена:

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

  <context:property-placeholder location="classpath:jdbc.properties"/>
  <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.nightsword.driverClassName}"/>
    <property name="url" value="${jdbc.nightsword.url}"/>
    <property name="username" value="${jdbc.nightsword.username}"/>
    <property name="password" value="${jdbc.nightsword.password}"/>
  </bean>

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="x.y"/>
  </bean>
</beans>

Для полноты здесь hibernate.properties:

hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.ejb.entitymanager_factory_name=something

И здесь вычитается вывод журнала уровня отладки как из org.springframework.orm, так и из org.hibernate. Вы можете видеть, как в 14: 40: 06,911 EntityManagerFactory регистрируется с первого раза, и сразу после этого LocalContainerEntityManagerFactoryBean начинает начинать все с самого начала. Да.

INFO: Deploying web application archive /opt/local/share/java/tomcat7/webapps/nightsword.war
14:40:06,149  INFO pool-2-thread-13 jpa.LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'default'
14:40:06,219 DEBUG pool-2-thread-13 type.BasicTypeRegistry:143 - Adding type registration boolean -> [email protected]

...

14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:62 - Initializing SessionFactoryRegistry : [email protected]
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:75 - Registering SessionFactory: a3219dd8-7d59-45ac-9a5a-0d13e38dbb04 (<unnamed>)
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:82 - Not binding SessionFactory to JNDI, no JNDI name configured
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:487 - Instantiated session factory
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1119 - Checking 0 named HQL queries
14:40:06,883 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1142 - Checking 0 named SQL queries
14:40:06,887 DEBUG pool-2-thread-13 internal.StatisticsInitiator:110 - Statistics initialized [enabled=false]
14:40:06,910 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:56 - Initializing EntityManagerFactoryRegistry : [email protected]
14:40:06,911 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:66 - Registering EntityManagerFactory: something 
14:40:06,967  INFO pool-2-thread-13 jpa.LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'default'
14:40:06,967 DEBUG pool-2-thread-13 type.BasicTypeRegistry:143 - Adding type registration boolean -> [email protected]

...

14:40:07,128 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:75 - Registering SessionFactory: 81a9b5a6-83aa-46ee-be68-d642e6fda584 (<unnamed>)
14:40:07,128 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:82 - Not binding SessionFactory to JNDI, no JNDI name configured
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:487 - Instantiated session factory
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1119 - Checking 0 named HQL queries
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1142 - Checking 0 named SQL queries
14:40:07,129 DEBUG pool-2-thread-13 internal.StatisticsInitiator:110 - Statistics initialized [enabled=false]
14:40:07,130 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:66 - Registering EntityManagerFactory: something 
14:40:07,130  WARN pool-2-thread-13 internal.EntityManagerFactoryRegistry:80 - HHH000436: Entity manager factory name (something) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

Ответ 1

Как вы инициализируете свой контекст приложения Spring? Используете ли вы Spring MVC?

Я видел иногда Spring конфигурацию MVC XML, импортирующую другое приложение. контекст XML, вызывающий одновременное выполнение нескольких beans, поскольку они объявлены в контексте приложения и контексте веб-приложения.

Ответ 2

Я столкнулся с той же проблемой, но в другом сценарии. EntityManagerFactoryRegistry выдает одно и то же предупреждение HHH000436, когда выполнение нескольких тестов в одном запуске (т.е. Тот же JVM) запускается из моей среды IDE.

Проблема может возникнуть в случае, если есть, по крайней мере, два тестовых класса, используя SpringJUnit4ClassRunner для загрузки различных тестовых контекстов приложения Spring, каждый из которых содержит EntityManagerFactory.

Основная причина заключается в том, что Hibernate поддерживает статический реестр экземпляров EntityManagerFactory, где создание второго экземпляра может вызвать столкновение с сообщением журнала. Итак, почему не первый экземпляр, снятый с регистрации после завершения первого теста? Обычно это происходит при уничтожении контекста приложения, содержащего этот экземпляр EntityManagerFactory. Причина, по которой это не происходит во время выполнения теста, заключается в том, что инфраструктура тестового контекста Spring кэширует все загруженные контексты, чтобы избежать повторной загрузки одного и того же контекста, потенциально необходимого для нескольких тестов. В результате beans в этих контекстах не уничтожается до тех пор, пока не завершится последний завершенный тест, а Hibernate просто соберет все экземпляры EntityManagerFactory, когда-либо созданные.

Это действительно не проблема, но если кто-то действительно раздражен предупреждающим сообщением, есть несколько возможных способов избежать этого:

  • Убедитесь, что экземпляры EntityManagerFactory получают другое имя (они заносятся по имени в реестре). Выделите конструктор EntityManagerFactoryImpl о том, как вызывается имя.
  • Используйте @DirtiesContext в тестовом классе, чтобы заставить SpringJUnit4ClassRunner закрыть контекст и удалить его из своего кэша контекста сразу после выполнения тестового класса.
  • Просто установите уровень ведения журнала EntityManagerFactoryRegistry на ошибку...

Надеюсь, это поможет кому-то.