在 aws 上部署 Spring 启动应用程序时,无法创建类型为 org.springframework.orm.jpa.SharedEntityManagerCreator 的内部 bean

时间:2021-05-10 19:39:52

标签: java spring spring-boot hibernate

我已在 AWS EC2 上部署了多租户 Spring 启动应用程序。该代码在本地系统中运行良好,但在 aws ec2 中运行 docker 后,应用程序失败并显示以下错误。

] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderReportListener' defined in URL [jar:file:/app-service.jar!/BOOT-INF/classes!/com/aic/autofluence/appservice/scheduler/kafkaReportListener/OrderReportListener.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reportFactoryImplData' defined in URL [jar:file:/app-service.jar!/BOOT-INF/classes!/com/aic/autofluence/appservice/scheduler/service/Impl/ReportFactoryImplData.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'orderReportRepository' defined in com.aic.autofluence.appservice.scheduler.repository.OrderReportRepository defined in @EnableJpaRepositories declared on TenantDatabaseConfig: Cannot create inner bean '(inner bean)#4293e066' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#4293e066': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
2021-05-10 18:58:57.081  INFO 1 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'masterdb-persistence-unit'
2021-05-10 18:58:57.082  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : masterdb-connection-pool - Shutdown initiated...
2021-05-10 18:58:57.099  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : masterdb-connection-pool - Shutdown completed.
2021-05-10 18:58:57.103  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2021-05-10 18:58:57.124  INFO 1 --- [           main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-05-10 18:58:57.147 ERROR 1 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.aic.autofluence.appservice.scheduler.service.Impl.ReportFactoryImplData required a bean named 'entityManagerFactory' that could not be found.

我的示例代码如下:

tenantConfig:EntityManagerFactory bean 本身不被识别。它在本地系统中运行良好,在 vm 中失败

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = { "x.x.x.x.scheduler.repository", "x.x.x.x.scheduler.model" })
@EnableJpaRepositories(basePackages = {"x.x.x.x..scheduler.repository", "x.x.x.x..scheduler.service"},
        entityManagerFactoryRef = "tenantEntityManagerFactory",
        transactionManagerRef = "tenantTransactionManager")
public class TenantDatabaseConfig {

   @Bean(name = "tenantJpaVendorAdapter")
    public JpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter ();
    }

    @Bean(name = "tenantTransactionManager")
    public JpaTransactionManager transactionManager(@Qualifier("tenantEntityManagerFactory") EntityManagerFactory tenantEntityManager) {
        JpaTransactionManager transactionManager = new JpaTransactionManager ();
        transactionManager.setEntityManagerFactory(tenantEntityManager);
        return transactionManager;
    }
    
    @Bean(name = "datasourceBasedMultitenantConnectionProvider")
    @ConditionalOnBean(name = "masterEntityManagerFactory")
    public MultiTenantConnectionProvider multiTenantConnectionProvider() {
        return new DataSourceBasedMultiTenantConnectionProviderImpl();
    }

    @Bean(name = "currentTenantIdentifierResolver")
    public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() {
        return new CurrentTenantIdentifierResolverImpl();
    }

    
    @Bean(name = "tenantEntityManagerFactory")
    @ConditionalOnBean(name = "datasourceBasedMultitenantConnectionProvider")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier("datasourceBasedMultitenantConnectionProvider")
                    MultiTenantConnectionProvider connectionProvider,
            @Qualifier("currentTenantIdentifierResolver")
                    CurrentTenantIdentifierResolver tenantResolver) {
        LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean ();
        //All tenant related entities, repositories and service classes must be scanned
        emfBean.setPackagesToScan("com.aic.autofluence.appservice");
        emfBean.setJpaVendorAdapter(jpaVendorAdapter());
        emfBean.setPersistenceUnitName("tenantdb-persistence-unit");
        Map<String, Object> properties = new HashMap<>();
        properties.put( Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
        properties.put( Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
        properties.put( Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
        properties.put( Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect");
        properties.put( Environment.SHOW_SQL, true);
        properties.put( Environment.FORMAT_SQL, true);
        properties.put( Environment.HBM2DDL_AUTO, "none");
        emfBean.setJpaPropertyMap(properties);
        return emfBean;
    }
}


**MasterConfig: It is configured properly working fine**

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"x.x.x.x.mastertenant.model",
        "x.x.x.x.mastertenant.repository"
},
        entityManagerFactoryRef = "masterEntityManagerFactory",
        transactionManagerRef = "masterTransactionManager")
public class MasterDatabaseConfig {

    private static final Logger LOG = LoggerFactory.getLogger(MasterDatabaseConfig.class);

    @Autowired
    private MasterDatabaseConfigProperties masterDbProperties;

    @Bean(name = "masterDataSource")
    public DataSource masterDataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource ();
        hikariDataSource.setUsername(masterDbProperties.getUsername());
        hikariDataSource.setPassword(masterDbProperties.getPassword());
        hikariDataSource.setJdbcUrl(masterDbProperties.getUrl());
        hikariDataSource.setDriverClassName(masterDbProperties.getDriverClassName());
        hikariDataSource.setPoolName(masterDbProperties.getPoolName());
        // HikariCP settings
        hikariDataSource.setMaximumPoolSize(masterDbProperties.getMaxPoolSize());
        hikariDataSource.setMinimumIdle(masterDbProperties.getMinIdle());
        hikariDataSource.setConnectionTimeout(masterDbProperties.getConnectionTimeout());
        hikariDataSource.setIdleTimeout(masterDbProperties.getIdleTimeout());
        LOG.info("Setup of masterDataSource succeeded.");
        return hikariDataSource;
    }

    @Primary
    @Bean(name = "masterEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean ();
        em.setDataSource(masterDataSource());
        em.setPackagesToScan(new String[]{x,x,x,x...});
        em.setPersistenceUnitName("masterdb-persistence-unit");
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter ();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibernateProperties());
        LOG.info("Setup of masterEntityManagerFactory succeeded.");
        return em;
    }

    @Bean(name = "masterTransactionManager")
    public JpaTransactionManager masterTransactionManager(@Qualifier("masterEntityManagerFactory") EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager ();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor ();
    }


    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put(org.hibernate.cfg.Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect");
        properties.put(org.hibernate.cfg.Environment.SHOW_SQL, true);
        properties.put(org.hibernate.cfg.Environment.FORMAT_SQL, true);
        properties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, "none");
        return properties;
    }

知道可能是什么问题吗?

谢谢

2 个答案:

答案 0 :(得分:-1)

<块引用>

代码在本地系统中运行良好,但在 aws ec2 中运行 docker 后,应用程序失败并显示以下错误。

您能否确保已尝试 mvn clean package 并将最新的工件部署到 EC2?


从堆栈跟踪来看,缺少一个名称为:entityManagerFactory 的 bean。你需要用正确的名字来引用这个bean。

Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

Parameter 0 of constructor in com.aic.autofluence.appservice.scheduler.service.Impl.ReportFactoryImplData required a bean named 'entityManagerFactory' that could not be found.

在您的代码中,

 @Primary
    @Bean(name = "masterEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory() {
 // ...
   @Bean(name = "tenantEntityManagerFactory")
    @ConditionalOnBean(name = "datasourceBasedMultitenantConnectionProvider")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
// ...

多个 bean 具有相同的类型 LocalContainerEntityManagerFactoryBean 和不同的名称masterEntityManagerFactorytenantEntityManagerFactory

如果您希望通过类型而不是名称来引用bean,则不能这样做,因为您有多个类型的bean > LocalContainerEntityManagerFactoryBean。要明确告诉 Spring 要注入哪个 bean,请根据您的定义指定 bean 名称。

根据您的堆栈跟踪,您在构造函数中通过名称 entityManagerFactory 引用了 bean。要解决此问题,您需要将参数名称从 entityManagerFactory 更改为 masterEntityManagerFactorytenantEntityManagerFactory

另一种指定要注入的 bean 名称的方法是使用 @Qualifier("beanName")Useful Guide

答案 1 :(得分:-1)

我已经通过删除 @ConditionalOnBean 注释解决了这个问题。感谢回复的人。

相关问题