Apache Camel无法识别JpaComponent:找不到oldDealer的EntityManager持久化提供者
问题场景
使用Apache Camel时遇到JpaComponent无法识别的问题,报错信息:
No Persistence provider for EntityManager named oldDealer
已通过@Autowired注入EntityManager并确认初始化完成,但Camel注册表中无法找到对应的持久化单元,且不想使用persistence.xml,希望仅通过application.properties完成配置。
相关配置与代码
application.properties
spring.datasource.olddealer.driver-class-name=org.mariadb.jdbc.Driver spring.datasource.olddealer.jdbcUrl=jdbc:mariadb://10.0.0.222/dealer_cabinet spring.datasource.olddealer.url=jdbc:mariadb://10.0.0.222/dealer_cabinet spring.datasource.olddealer.username=dealer_cabinet spring.datasource.olddealer.password= spring.datasource.newdealer.driver-class-name=org.mariadb.jdbc.Driver spring.datasource.newdealer.jdbcUrl=jdbc:mariadb://10.0.0.222/dealer spring.datasource.newdealer.url=jdbc:mariadb://10.0.0.222/dealer spring.datasource.newdealer.username=dealer_cabinet spring.datasource.newdealer.password=
OldDealerConfiguration.java
@Configuration @EnableJpaRepositories( entityManagerFactoryRef = OldDealerConfiguration.ENTITY_MANAGER_FACTORY, transactionManagerRef = OldDealerConfiguration.TRANSACTION_MANAGER, basePackages = OldDealerConfiguration.JPA_REPOSITORY_PACKAGE ) public class OldDealerConfiguration { public static final String ENTITY_MANAGER_FACTORY = "oldDealerEntityManagerFactory"; public static final String TRANSACTION_MANAGER = "oldDealerTransactionManager"; public static final String JPA_REPOSITORY_PACKAGE = "com.flytech.camelrouter.repository.olddealer"; @Bean(name = "oldDealerProperties") @Primary @ConfigurationProperties("spring.datasource.olddealer") DataSourceProperties oldDealerDataSourceProperties(){ return new DataSourceProperties(); } @Bean(name = "oldDealerDataSource") @Primary @ConfigurationProperties(prefix="spring.datasource.olddealer") public DataSource oldDealerDataSource(@Qualifier("oldDealerProperties") DataSourceProperties dataSourceProperties) { return dataSourceProperties.initializeDataSourceBuilder().build(); } @Bean(name = ENTITY_MANAGER_FACTORY) public LocalContainerEntityManagerFactoryBean oldDealerEntityManagerFactoryBean( @Qualifier("oldDealerDataSource") DataSource dataSource){ LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean(); emfb.setPersistenceUnitName("oldDealer"); HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MariaDBDialect"); emfb.setJpaVendorAdapter(vendorAdapter); emfb.setDataSource(dataSource); emfb.setPackagesToScan("com.flytech.camelrouter.entity.olddealer"); emfb.afterPropertiesSet(); return emfb; } @Bean(name = TRANSACTION_MANAGER) public PlatformTransactionManager oldDealerTransactionManager( @Qualifier(ENTITY_MANAGER_FACTORY) EntityManagerFactory entityManagerFactory){ JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); jpaTransactionManager.setEntityManagerFactory(entityManagerFactory); return jpaTransactionManager; } @Bean("oldDealerJpaComponent") public JpaComponent oldDealerJpaComponent( @Qualifier(OldDealerConfiguration.ENTITY_MANAGER_FACTORY)EntityManagerFactory entityManagerFactory, CamelContext camelContext){ JpaComponent jpaComponent = new JpaComponent(); jpaComponent.setEntityManagerFactory(entityManagerFactory); jpaComponent.setCamelContext(camelContext); return jpaComponent; } }
(注:原代码中@org.apache.camel.language.bean.Bean注解为冗余配置,已移除)
SecondTestRouter.java
@Component public class SecondTestRouter extends RouteBuilder { @Autowired @Qualifier("oldDealerJpaComponent") JpaComponent jpaComponent; @Autowired @PersistenceContext(unitName = "oldDealer") EntityManager oldEntityManager; @Autowired @PersistenceContext(unitName = "newDealer") EntityManager newEntityManager; @Override public void configure() throws Exception { from("timer://readDataFromOldDealer?period=60000") .to("jpa:com.flytech.camelrouter.entity.olddealer.Network?" + "resultClass=com.flytech.camelrouter.entity.olddealer.Network&" + "persistenceUnit=oldDealer&nativeQuery=SELECT n.dealer, n.network, n.location, n.benefit, n.prefix, n.cid, n.locality_id, u.full_name, u.email, u.phone FROM networks n INNER join user u on n.dealer = u.username;") .log("${body.dealer}"); } }
问题分析与解决方案
核心原因
路由中使用jpa:端点并指定persistenceUnit=oldDealer时,Camel会默认尝试从JPA全局持久化单元注册表(依赖persistence.xml的方式)查找,而非你通过Spring Bean配置的EntityManagerFactory。虽然你已创建自定义oldDealerJpaComponent,但路由未使用该实例,而是调用了Camel默认的JPA组件。
解决步骤
直接引用自定义JpaComponent实例
修改路由代码,通过bean:前缀调用自定义组件并指定JPA操作参数:@Override public void configure() throws Exception { from("timer://readDataFromOldDealer?period=60000") .toD("bean:oldDealerJpaComponent?operation=findByNativeQuery&nativeQuery=SELECT n.dealer, n.network, n.location, n.benefit, n.prefix, n.cid, n.locality_id, u.full_name, u.email, u.phone FROM networks n INNER join user u on n.dealer = u.username;&resultClass=com.flytech.camelrouter.entity.olddealer.Network") .log("${body.dealer}"); }注册自定义组件为Camel端点前缀
在oldDealerJpaComponent的Bean定义中,将组件添加到Camel上下文并指定自定义前缀:@Bean("oldDealerJpa") public JpaComponent oldDealerJpaComponent( @Qualifier(OldDealerConfiguration.ENTITY_MANAGER_FACTORY)EntityManagerFactory entityManagerFactory, CamelContext camelContext){ JpaComponent jpaComponent = new JpaComponent(); jpaComponent.setEntityManagerFactory(entityManagerFactory); camelContext.addComponent("oldDealerJpa", jpaComponent); return jpaComponent; }之后路由可直接使用自定义前缀调用:
from("timer://readDataFromOldDealer?period=60000") .to("oldDealerJpa:com.flytech.camelrouter.entity.olddealer.Network?" + "resultClass=com.flytech.camelrouter.entity.olddealer.Network&" + "nativeQuery=SELECT n.dealer, n.network, n.location, n.benefit, n.prefix, n.cid, n.locality_id, u.full_name, u.email, u.phone FROM networks n INNER join user u on n.dealer = u.username;") .log("${body.dealer}");验证EntityManagerFactory初始化
可在oldDealerEntityManagerFactoryBean方法中添加日志,确认persistenceUnitName已正确设置为oldDealer,且EntityManagerFactory成功创建。
额外注意事项
- 多数据源JPA环境下,
@Primary注解需正确使用,确保Spring能识别默认的EntityManagerFactory,当前配置中oldDealer相关Bean的@Primary设置正确。 - 存在多个EntityManagerFactory时,必须明确指定Camel JPA组件使用的实例,自定义JpaComponent是最可靠的方式。
内容的提问来源于stack exchange,提问作者Suleyman Batyrov

