我有一个关于Sping Boot 和使用JpaRepositories的多个数据源的设置的问题。
[*4编辑如下 *]
项目的结构如下所示:com/mycompany/schema/AbstractJpaConfig com/mycompany/schema/domain_A/AJpaConfiguration com/mycompany/schema/domain_A/entity/AEntity com/mycompany/schema/domain_A/repository/ARepository com/mycompany/schema/domain_B/BJpaConfiguration com/mycompany/schema/domain_B/entity/BEntity com/mycompany/schema/domain_B/repository/BRepository
因此,我有两个域(A和B),DataSource的设置是分开处理的。
抽象的JPA配置类用于减少冗余,并使用一个自定义的DataSourceManager来处理DataSources:
public abstract class AbstractJpaConfiguration {
private final DataSourceManager dataSources;
public AbstractJpaConfiguration(DataSourceManager dataSources) {
this.dataSources = dataSources;
}
protected abstract String persistenceUnitName();
protected abstract Class<?> packageEntityClass();
protected abstract DataSource useDataSource(DataSourceManager dataSources);
public abstract LocalContainerEntityManagerFactoryBean entityManagerFactoryBean();
public abstract PlatformTransactionManager transactionManagerBean();
public abstract LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean();
protected LocalContainerEntityManagerFactoryBean buildEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(useDataSource(dataSources));
em.setPersistenceUnitName(persistenceUnitName() + "PU");
em.setBeanName(persistenceUnitName() + "EntityManager");
em.setPackagesToScan(packageEntityClass().getPackage().getName());
em.setJpaPropertyMap(persistenceProperties());
em.setJpaVendorAdapter(jpaVendorAdapter());
return em;
}
protected Map<String, String> persistenceProperties() {
Map<String, String> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "validate");
return properties;
}
protected JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(false);
adapter.setGenerateDdl(false);
return adapter;
}
protected PlatformTransactionManager buildTransactionManager() {
LocalContainerEntityManagerFactoryBean emfBean = getEntityManagerFactoryBean();
EntityManagerFactory emf = emfBean.getObject();
return new JpaTransactionManager(emf);
}
}
位于域A包中的配置的实现如下所示:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.mycompany.schema.domain_A",
entityManagerFactoryRef = "AEntityManagerFactory",
transactionManagerRef = "ATransactionManager")
@EntityScan(basePackages = "com.mycompany.schema.domain_A")
@DependsOn("flywayMigrationInitializer")
public class AJpaConfiguration extends AbstractJpaConfiguration {
@Autowired
public AJpaConfiguration(DataSourceManager dataSources) {
super(dataSources);
}
@Override
protected Class<?> packageEntityClass() {
return getClass(); // This class is located in the entity class package
}
@Override
protected String persistenceUnitName() {
return "a";
}
@Override
protected DataSource useDataSource(DataSourceManager dataSources) {
return dataSources.domainADataSource();
}
@Bean("aEntityManagerFactory")
@Override
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
return buildEntityManagerFactory();
}
@Bean("aTransactionManager")
@Override
public PlatformTransactionManager transactionManagerBean() {
return buildTransactionManager();
}
@Override
public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() {
return entityManagerFactoryBean();
}
}
然后,将实际的存储库定义为JpaRepository:
@Repository
public interface ARepository extends JpaRepository<AEntity, Long> {
}
根据应用程序日志,这 * 似乎 * 可以工作:
2018-12-14 09:45:02.997 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2018-12-14 09:45:02.997 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2018-12-14 09:45:03.012 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 9ms. Found 1 repository interface.
2018-12-14 09:45:03.029 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2018-12-14 09:45:03.029 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2018-12-14 09:45:03.085 INFO 13867 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 56ms. Found 1 repository interface.
在此之后,Flyway迁移成功,持久单元启动:
2018-12-14 09:45:06.459 INFO 13867 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: aPU
...]
2018-12-14 09:45:06.544 INFO 13867 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate Core {5.3.7.Final}
2018-12-14 09:45:06.546 INFO 13867 --- [ restartedMain] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2018-12-14 09:45:06.746 INFO 13867 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2018-12-14 09:45:06.922 INFO 13867 --- [ restartedMain] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
2018-12-14 09:45:07.976 INFO 13867 --- [ restartedMain] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2018-12-14 09:45:08.066 INFO 13867 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'aPU'
但是,当我尝试将存储库自动连接到服务时:
@Service
public class MyService {
private final ARepository repository;
@Autowired
public MyService(ARepository repository) {
this.repository = repository;
}
// ...
}
这是我在日志中收到的错误消息:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'MyService' defined in URL [jar:file:...]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.schema.domain_A.repository.ARepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:767) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1308) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1154) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1239) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:855) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:758) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 106 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.schema.domain_A.repository.ARepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1646) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:855) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:758) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 120 common frames omitted
我希望提供的信息能帮助解决这个问题。
如果没有,我很乐意提供更多信息。
感谢您的参与,祝您愉快
- Alexandria
---编辑---
我在配置类中放置了两个断点,并得到了一些新信息:
呼叫建立LocalContainerEntityManagerFactoryBean
的方法,但在呼叫PlatformTransactionManager
Bean方法之前,应用程序因缺少Bean而停止。
我忽略的是,所讨论的服务(需要JpaRepository子类型)正在实现Spring Security UserDetailsManager
接口。看起来Spring Security系统正在尝试示例化UserDetailsManager服务,然后才能创建由@EnableJpaRepositories
拾取的JpaRepository Bean。
有什么解决办法吗?
---编辑2 ---
我尝试对AJpaConfiguration类执行@Import
操作,但没有任何改变。然而,仔细查看bean示例化日志,我发现了以下消息:
2018-12-14 11:52:08.395 DEBUG 22417 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'aEntityManagerFactory'
2018-12-14 11:52:08.395 DEBUG 22417 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'aJpaConfig'
因此,Sping Boot 将为LocalContainerEntityManagerFactoryBean
选择@Bean注解,但既不创建EntityManagerFactory示例,也不为PlatformTransactionManager
选择@Bean注解。
---编辑3 ---
我设置了@Autowired选项required = false
,现在它开始拾取bean并示例化存储库--但只是在示例化了需要它们的服务之后,因此没有注入它们。
2018-12-14 13:25:30.484 DEBUG 31932 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'aEntityManager'
2018-12-14 13:25:33.035 DEBUG 31932 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'aTransactionManager'
2018-12-14 13:25:34.852 DEBUG 31932 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'aRepository'
我如何才能在其他事情之前创建bean呢?这似乎可以解决问题。
---编辑4 ---
感谢@RobertNiestroj的提示,我将@Lazy
添加到@Autowired
注解中,这使得它们在存储库之后被初始化。
但现在,出现了一个不同的错误:java.lang.IllegalArgumentException: interface com.mycompany.schema.domain_A.repository.ARepository is not visible from class loader
个
我还应该提到这个应用程序是基于Maven模块构建的:- Schema模块(JPA设定、储存库和实体类别)- Core模块(应用程序设定和特性类别)- [使用Core和Schema的其他模块] - Main模块(Spring-Boot应用程序类别)
2条答案
按热度按时间ct3nt3jp1#
您是否尝试过@Repository(name =“repository”)?IIRC,如果不提供名称,则会创建一个与类匹配的名称的组件,在本例中为“aRepository”。因此,当自动配置repository变量时,没有名为“repository”的组件,从而导致无限定Bean异常。
fruv7luv2#
请尝试如下自动安装并检查