You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring6+Tomcat10+Java17环境下EntityManagerFactory创建失败求助

问题

我有一个基于Maven、EclipseLink、JPA、Spring 5、JSF2.3、Java 8、PrimeFaces 11的Web应用,原本部署在Tomcat 8.5上。为完成软件现代化,已成功迁移至Tomcat 9+Java 17并保留Spring 5,但在进一步迁移至Tomcat 10.0+Java 17,同时升级所有依赖至Jakarta生态(含Spring 6)时卡在EntityManager配置环节。

应用通过继承org.springframework.web.servlet.support.AbstractDispatcherServletInitializer的类配置,在onStartup方法中定义Faces Servlet等JSF/PrimeFaces组件,getRootConfigClasses方法中包含RepositoryConfig等配置类。

RepositoryConfig代码

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("here.my.package.with.repositories")
public class RepositoryConfig implements TransactionManagementConfigurer {
    
    protected Logger logger = LogManager.getLogger(this.getClass());
    
    @Autowired 
    @Qualifier("config")
    private Config config;  
    
    @Bean(name="entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        
        emf.setDataSource(dataSource());
        
        emf.setPackagesToScan(new String[] { 
                "here.my.package.with.entities"
                });
        
        emf.setJpaVendorAdapter(jpaAdapter());
        
        Properties jpaProperties = new Properties();
        
        JpaDialect jpaDialect = new EclipseLinkJpaDialect();
        emf.setJpaDialect(jpaDialect);
        
        jpaProperties.put("eclipselink.weaving", "false");
        
        
        emf.setJpaProperties(jpaProperties);

        return emf;
    }
    
    
    @Bean(name="jpaAdapter")
    public EclipseLinkJpaVendorAdapter jpaAdapter() {
        EclipseLinkJpaVendorAdapter hjva = new EclipseLinkJpaVendorAdapter();
        hjva.setDatabasePlatform("org.eclipse.persistence.platform.database.MySQLPlatform");
        hjva.setGenerateDdl(false);
        hjva.setShowSql(false);
        return hjva;
    }
    
    @Bean(name="dataSource")
    public DataSource dataSource() {
        JndiTemplate template = new JndiTemplate();
        DataSource ds = null;
        try {
            ds = (DataSource) template.lookup("java:/comp/env/" + config.get("repository.jndi.name"));
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return ds;
    }

    
    @Bean(name="transactionManager")
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        try {
            jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
            jpaTransactionManager.setDataSource(dataSource());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return jpaTransactionManager;
    } 
    
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return transactionManager();
    }   
    
    @Bean(name="persistenceAnnotation")
    public PersistenceAnnotationBeanPostProcessor persistenceAnnotation() {
        return new PersistenceAnnotationBeanPostProcessor();
    }
}

错误日志

Error creating bean with name 'entityManagerFactory' defined in it.baseapp.conf.RepositoryConfig: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'entityManagerFactory' threw exception with message: Error creating bean with name 'entityManagerFactory' defined in it.baseapp.conf.RepositoryConfig: Failed to instantiate
..
Error creating bean with name 'entityManagerFactory' defined in it.baseapp.conf.RepositoryConfig: Unexpected exception during bean creation
..
it always repeats this error for several lines
...
12:47:54.521 [main] ERROR it.baseapp.conf.RepositoryConfig$$SpringCGLIB$$0 - @Bean method RepositoryConfig.entityManagerFactory called as bean reference for type [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] but overridden by non-compatible bean instance of type [jdk.proxy3.$Proxy76]. Overriding bean of same name declared in: it.baseapp.conf.RepositoryConfig
[EL Info]: 2023-07-05 12:47:55.433--ServerSession(2050864629)--EclipseLink, version: Eclipse Persistence Services - 4.0.2.v202306161219
[EL Warning]: metamodel: 2023-07-05 12:47:56.449--The collection of metamodel types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units.  Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element
[EL Warning]: metamodel: 2023-07-05 12:47:57.378--The collection of metamodel [ManagedType] types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units.  Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.  The lookup on [class here.my.package.with.entities.OneOfMyEntities] will return null.
[EL Warning]: metamodel: 2023-07-05 12:47:57.618--The collection of metamodel [ManagedType] types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units.  Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.  The lookup on [class here.my.package.with.entities.OneOfMyEntities] will return null.
12:47:57.637 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed  

依赖版本

<dependency>   
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>4.0.2</version>
</dependency>

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>3.1.1</version>
</dependency>

<!-- 其他Spring依赖版本为6.0.10 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>6.0.10</version>
</dependency>  

解决方案

1. 修复EntityManagerFactory代理冲突问题

错误日志中overridden by non-compatible bean instance of type [jdk.proxy3.$Proxy76]的核心原因是在transactionManager()方法中直接调用entityManagerFactory()创建新实例,而非依赖Spring容器注入已管理的Bean。

修改transactionManager()方法,通过注入方式获取EntityManagerFactory:

@Bean(name="transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    try {
        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
        jpaTransactionManager.setDataSource(dataSource());
    } catch (Exception e) {
        logger.error(e.getMessage());
    }
    return jpaTransactionManager;
} 

Spring会自动将entityManagerFactory Bean(由LocalContainerEntityManagerFactoryBean生成的代理对象)注入到该方法中,避免重复创建实例导致的冲突。

2. 确保实体类适配Jakarta生态

EclipseLink 4.x是Jakarta EE版本,仅识别jakarta.persistence包下的注解,而旧代码中的实体类可能还在使用javax.persistence注解。需要将所有实体类的注解替换为Jakarta版本:

  • 将javax.persistence.Entity → jakarta.persistence.Entity
  • 将javax.persistence.Id → jakarta.persistence.Id
  • 其他JPA注解(如@Table、@Column、@OneToMany等)均需替换为jakarta.persistence下的对应注解

3. 优化实体类扫描配置

如果替换注解后仍出现metamodel为空的警告,可补充以下配置确保Spring正确扫描实体类:

  • 确认emf.setPackagesToScan的包路径完全正确(注意拼写、大小写)
  • 添加jpaProperties.put("eclipselink.persistencexml", "META-INF/persistence.xml")指定persistence.xml路径(可选,若使用xml配置实体类)
  • 若使用persistence.xml,需添加<exclude-unlisted-classes>false</exclude-unlisted-classes>并列出所有实体类,或直接依赖Spring的包扫描

4. 移除冗余的PersistenceAnnotationBeanPostProcessor

Spring 6已自动支持@PersistenceContext、@PersistenceUnit等注解的处理,无需手动注册PersistenceAnnotationBeanPostProcessor,可删除该Bean定义:

// 移除以下代码
@Bean(name="persistenceAnnotation")
public PersistenceAnnotationBeanPostProcessor persistenceAnnotation() {
    return new PersistenceAnnotationBeanPostProcessor();
}

5. 验证EclipseLink与Spring的兼容性

确保使用的EclipseLinkJpaVendorAdapter是Spring 6提供的Jakarta版本(包路径为org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter),而非旧的javax版本。同时确认EclipseLink 4.0.2与Spring 6.0.10、Spring Data JPA 3.1.1版本兼容。


内容的提问来源于stack exchange,提问作者iljkr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 06:48:08