Spring Boot集成EclipseLink启动报错:找不到entityManagerFactory Bean
问题背景
1. EclipseLink JPA配置类
@EnableTransactionManagement @EnableJpaRepositories({ "com.soib.repositories", "com.notification.repositories"}) @Slf4j @Configuration public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { protected EclipseLinkJpaConfiguration( DataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager) { super(dataSource, properties, jtaTransactionManager); } @Override protected AbstractJpaVendorAdapter createJpaVendorAdapter() { return new EclipseLinkJpaVendorAdapter(); } @Bean @Primary public static JpaProperties properties() { final JpaProperties jpaProperties = new JpaProperties(); jpaProperties.setShowSql(false); jpaProperties.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform"); return jpaProperties; } @Override protected Map<String, Object> getVendorProperties() { HashMap<String, Object> map = new HashMap<>(); map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode()); return map; } private String detectWeavingMode() { return InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static"; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setPersistenceUnitName("soib-backoffice-entities"); factoryBean.setPackagesToScan("eu.europa.ec.oib.kwbo.model"); factoryBean.setJpaVendorAdapter(jpaVendorAdapter); Properties jpaProperties = new Properties(); jpaProperties.setProperty("eclipselink.target-database", "org.eclipse.persistence.platform.database.OraclePlatform"); jpaProperties.setProperty("eclipselink.target-server", "WebLogic"); jpaProperties.setProperty("eclipselink.logging.level", "WARNING"); jpaProperties.setProperty("eclipselink.logging.level.sql", "WARNING"); jpaProperties.setProperty("eclipselink.logging.logger", "DefaultLogger"); jpaProperties.setProperty("eclipselink.cache.shared.default", "false"); jpaProperties.setProperty("eclipselink.weaving", "false"); jpaProperties.setProperty("eclipselink.jdbc.fetch-size", "200"); factoryBean.setJpaProperties(jpaProperties); return factoryBean; } @Bean public JpaVendorAdapter jpaVendorAdapter() { EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter(); vendorAdapter.setShowSql(false); vendorAdapter.setGenerateDdl(false); vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform"); return vendorAdapter; } }
2. application.properties配置
# JPA general settings spring.jpa.show-sql=false spring.jpa.generate-ddl=false spring.jpa.database-platform=org.eclipse.persistence.platform.database.OraclePlatform # EclipseLink-specific properties spring.jpa.properties.eclipselink.target-database=org.eclipse.persistence.platform.database.OraclePlatform spring.jpa.properties.eclipselink.target-server=WebLogic spring.jpa.properties.eclipselink.logging.level=WARNING spring.jpa.properties.eclipselink.logging.level.sql=WARNING spring.jpa.properties.eclipselink.logging.logger=DefaultLogger spring.jpa.properties.eclipselink.cache.shared.default=false spring.jpa.properties.eclipselink.weaving=false spring.jpa.properties.eclipselink.jdbc.fetch-size=200
3. 启动错误日志
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#a30810': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113) at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:688) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:505) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:374) ... 58 common frames omitted Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:874) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1358) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
解决方法
问题根源在于配置类同时继承JpaBaseConfiguration和自定义entityManagerFactory、jpaVendorAdapter Bean,导致Spring Boot自动配置与自定义配置冲突,无法生成正确的entityManagerFactory Bean。
步骤1:移除冲突的自定义Bean方法
删除配置类中自定义的entityManagerFactory和jpaVendorAdapter方法,因为继承JpaBaseConfiguration已经会自动生成这些核心Bean,重复定义会引发初始化混乱。修改后的配置类如下:
@EnableTransactionManagement @EnableJpaRepositories({ "com.soib.repositories", "com.notification.repositories"}) @Slf4j @Configuration public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { protected EclipseLinkJpaConfiguration( DataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager) { super(dataSource, properties, jtaTransactionManager); } @Override protected AbstractJpaVendorAdapter createJpaVendorAdapter() { return new EclipseLinkJpaVendorAdapter(); } @Override protected Map<String, Object> getVendorProperties() { HashMap<String, Object> map = new HashMap<>(); map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode()); return map; } private String detectWeavingMode() { return InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static"; } }
步骤2:保留application.properties配置
无需修改application.properties中的内容,JpaBaseConfiguration会自动读取并应用这些配置参数,无需在代码中重复设置。
步骤3:确保配置类被Spring扫描
确认EclipseLinkJpaConfiguration所在包被Spring Boot组件扫描覆盖,或者在启动类上通过@Import(EclipseLinkJpaConfiguration.class)显式引入该配置类。
额外说明
如果确实需要完全自定义entityManagerFactory,则不要继承JpaBaseConfiguration,直接使用@Configuration注解,并在@EnableJpaRepositories中通过entityManagerFactoryRef属性指定自定义Bean的名称(若名称不是默认的entityManagerFactory)。但更推荐使用继承JpaBaseConfiguration配合application.properties的方式,能更好地利用Spring Boot的自动配置能力。
内容的提问来源于stack exchange,提问作者Nunyet Calçada

