Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Исключение Hibernate: не удалось напрямую создать экземпляр управляемого компонента

Автор вопроса: Barry ChapmanОтветов: 1

У меня есть случай, когда мне нужно два экземпляра EntityManager, один для чтения/записи и один для отслеживания аудита.

Мы создали два экземпляра Entity Manager, выполнив следующие действия:

// в App.java мы добавили следующую аннотацию:

@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })

Затем создал два менеджера сущностей, например: 1:

package com.vw.asa.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@EnableTransactionManagement
@Configuration
@EnableJpaRepositories(basePackages = "com.vw.asa.repositories", entityManagerFactoryRef = "entityManager", transactionManagerRef = "transactionManager")
public class PrimaryDatasource {

    /**
     * Primary Datasource Configuration
     * @return
     */
    @Bean(name = "dataSource")      // 3
    @Primary
    @ConfigurationProperties(prefix = "primary.datasource.mysql")
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @PersistenceContext(unitName = "primary")   // 4
    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder.dataSource(mysqlDataSource())
                .persistenceUnit("primary")
                .properties(jpaProperties())
                .packages("com.vw.asa").build();
    }

    private Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.ejb.naming_strategy", new SpringPhysicalNamingStrategy());
        return props;
    }

}

2:

package com.vw.asa.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@EnableTransactionManagement
@Configuration
@EnableJpaRepositories(basePackages = "com.vw.asa.repositories", entityManagerFactoryRef = "secondaryMySqlEntityManager", transactionManagerRef = "secondaryTransactionManager")
public class SecondaryDatasource {

    /**
     * Secondary Datasource Configuration
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "secondary.datasource.mysql")
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @PersistenceContext(unitName = "secondary")
    @Bean(name = "secondaryMySqlEntityManager")
    public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return  builder.dataSource(mysqlDataSource()).properties(jpaProperties()).persistenceUnit("secondary").packages("au.com.myblog.domain").build();
    }

    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(mySqlEntityManagerFactory(builder).getObject());
        tm.setDataSource(mysqlDataSource());
        return tm;
    }

    private Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        // naming strategy to put underscores instead of camel case
        // as per auto JPA Configuration
        props.put("hibernate.ejb.naming_strategy", new SpringPhysicalNamingStrategy());
        props.put("hibernate.hbm2ddl.auto", "none");
        return props;
    }

}

Однако при запуске приложения возникает это исключение:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/vw/asa/config/PrimaryDatasource.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: primary] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.InstantiationException: Could not instantiate managed bean directly : com.vw.asa.listeners.AttachmentListener
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
    ... 121 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: primary] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.InstantiationException: Could not instantiate managed bean directly : com.vw.asa.listeners.AttachmentListener
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:403)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:378)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792)
    ... 128 more
Caused by: org.hibernate.InstantiationException: Could not instantiate managed bean directly : com.vw.asa.listeners.AttachmentListener
    at org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer.produceBeanInstance(FallbackBeanInstanceProducer.java:45)
    at org.hibernate.resource.beans.container.spi.FallbackContainedBean.<init>(FallbackContainedBean.java:23)
    at org.hibernate.resource.beans.internal.ManagedBeanRegistryImpl.getBean(ManagedBeanRegistryImpl.java:58)
    at org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl.resolveEntityCallbacks(CallbackBuilderLegacyImpl.java:200)
    at org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl.buildCallbacksForEntity(CallbackBuilderLegacyImpl.java:74)
    at org.hibernate.event.service.internal.EventListenerRegistryImpl.prepare(EventListenerRegistryImpl.java:146)
    at org.hibernate.boot.internal.MetadataImpl.initSessionFactory(MetadataImpl.java:376)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:211)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1237)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
    ... 132 more
Caused by: java.lang.NoSuchMethodException: com.vw.asa.listeners.AttachmentListener.<init>()
[2021-02-21 08:43:48,090] Artifact vw-asa:war exploded: Error during artifact deployment. See server log for details.
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getDeclaredConstructor(Class.java:2178)
    at org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer.produceBeanInstance(FallbackBeanInstanceProducer.java:40)
    ... 144 more

Идея заключалась в том, что мы могли определить, какой EM использовать с данной транзакцией. Чем это вызвано? Он выдает разные ошибки, если я переименую его из EntityManagerFactory

  • Причина ошибки в трассировке стека и, вероятно, не связана с несколькими источниками данных: spring Could not instantiate managed bean directly : com.vw.asa.listeners.AttachmentListener, потому что метод init не существует. AllirionX 22.02.2021
  • @AllirionX Что вызывает инициализацию? Зачем нужен метод init? Barry Chapman 22.02.2021
  • Бинам нужны конструкторы по умолчанию, если вы хотите, чтобы Spring их инициализировал. Вы можете прочитать этот очень похожий вопрос SO: > stackoverflow.com/questions/18023870/ AllirionX 22.02.2021

spring-bootjavaspringaudit-loggingentitymanager

Ответы

Ответ 1 · рейтинг 1 · Rafael Ide

Проблема в том, что ваш EntityListener не предоставляет конструктор по умолчанию (без аргументов), который требуется Hibernate для создания экземпляра прослушивателя.

Если вы используете Hibernate 5.3 или выше, вы можете заставить Spring предоставить эти bean-компоненты для Hibernate, установив BeanContainer в EntityManagerFactory следующим образом:

public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder, ConfigurableListableBeanFactory beanFactory) {
    LocalContainerEntityManagerFactoryBean emfb = builder.dataSource(mysqlDataSource())
            .persistenceUnit("primary")
            .properties(jpaProperties())
            .packages("com.vw.asa").build();
    emfb.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
    return emfb;
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы