【问题标题】:Cannot create inner beanof type org.springframework.orm.jpa.SharedEntityManagerCreator error while Spring boot application deployed on aws在 aws 上部署 Spring 启动应用程序时无法创建类型为 org.springframework.orm.jpa.SharedEntityManagerCreator 的内部 bean
【发布时间】:2021-08-01 05:28:46
【问题描述】:

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

] 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;
    }

任何想法可能是什么问题?

谢谢

【问题讨论】:

  • 有人对此有想法吗?
  • 你的意思是在上面的“x.x.x.x..scheduler.repository”中的包路径中有两个句点。这可能刚刚发生在您编辑时,但只是检查。
  • @Atmas x.x.x.x.. 是包名因为我不允许暴露它,所以我只是放了一些随机数据,比如 x.x.x.x ......我问的问题与 bean 创建有关。如果您有任何想法,请发表评论吗?
  • @Atmas 关于编辑在这里不是问题。 bean 创建没有发生,我观察到的是在 TenantDatabaseConfig 类中,指向与 MasterDatabaseConfig 相关的 bean,它本身在 TenantDatabaseConfig 类中未被识别。如果对此有任何想法,请对此发表评论
  • 我想知道这是否只是配置冲突的约定。你愿意用“entityManagerFactory”替换你的bean名称和引用它的“tenantEntityManagerFactory”的所有实例吗?这样,它与方法名称(即 entityManagerFactory)一致,并且与我在网上看到的其他示例一致。

标签: java spring spring-boot hibernate


【解决方案1】:

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

【讨论】:

  • 奇怪。与我们今天早些时候谈论它但它没有识别细节的时间相比有什么变化?早期的测试没有完全部署或什么?很高兴你重新上线。
  • 但你提到了,"the code just works fine in the local system, "。如果@ConditionalOnBean 使您的应用程序无法运行,那它怎么会是“works fine in the local system”?
  • @justthink 这实际上是我的问题。在 aws 为什么 ConditionalOnBean 注释不起作用。我仍然在窃听一些文章,以同样的方式与人们联系。现在由于它能够通过删除 ConditionalOnBean 来识别 bean,所以我采用了 .如果您对此有任何想法或解释,请在此处发表评论
  • @Atmas everthing 已部署。我通过在tenantDatabaseConfig 的每一行中保留日志语句再次开始调试。我发现类正在被正确扫描,但它指向应用程序中的 ConditionalOnBean 注释,该注释部署在未处理的 aws 上。所以尝试删除该注释并首先在我的本地尝试它在识别 bean 方面工作得很好,同样部署在 VM 中也可以工作
  • 确实有效。这两天为此苦苦挣扎。谢谢
【解决方案2】:

代码在本地系统中运行良好,但在 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

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

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

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

【讨论】:

  • @justhtink 在这里我仅通过参数名称引用 bean。我没有得到您指出的确切位置 @EnableJpaRepositories(basePackages = {"x.x.x.x..scheduler.repository", "x.x.x.x..scheduler.service"}, entityManagerFactoryRef = "tenantEntityManagerFactory", transactionManagerRef = "tenantTransactionManager")
  • 全局搜索entityManagerFactory,区分大小写。
  • @Arundhathi D 不可能完全相同的@ConditionalOnBean 注释会破坏AWS EC2 服务器中的bean 创建,同时不会破坏本地系统中的bean 创建。你问错了。
  • 通过提供 ConditionalOnBean 注释来尝试一次 mutitenant 应用程序。如果您面临同样的问题,那很好,也请告诉我。我不认为这里有问题。谢谢
猜你喜欢
  • 2013-11-08
  • 1970-01-01
  • 2012-03-05
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多