Spring Boot – JpaRepository не инициализируется при использовании нескольких источников данныхJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Spring Boot – JpaRepository не инициализируется при использовании нескольких источников данных

Сообщение Anonymous »

У меня есть вопрос относительно Spring 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), причем настройка источника данных обрабатывается отдельно.

Абстрактный класс конфигурации JPA используется для уменьшения избыточности и использует собственный DataSourceManager, который обрабатывает источники данных:

Код: Выделить всё

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 persistenceProperties() {
Map 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 {
}
Это похоже работает, судя по журналам приложений:

Код: Выделить всё

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
Надеюсь, предоставленная информация поможет решить эту проблему.

Если нет, я буду рад предоставить дополнительную информацию.

Спасибо, что уделили время, и хорошего дня.

– Александр

--- Изменить ---

Я поставил две точки останова в конфигурацию классы и получили некоторую новую информацию:

Метод для создания LocalContainerEntityManagerFactoryBean вызывается, но приложение останавливается из-за отсутствия bean-компонента до вызова метода bean-компонента PlatformTransactionManager.

Что я упустил из виду, так это то, что рассматриваемая служба, для которой требуется подтип JpaRepository, реализует интерфейс Spring Security UserDetailsManager.
/>Похоже, что система Spring Security пытается создать экземпляр службы UserDetailsManager до того, как будут созданы компоненты JpaRepository, выбранные @EnableJpaRepositories.

Есть ли какое-нибудь решение для этого?

--- Редактировать 2 ---

Я пытался @Import Класс AJpaConfiguration, который ничего не изменил.
Однако, присмотревшись к журналам создания экземпляров компонента, я обнаружил следующие сообщения:

Код: Выделить всё

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'
Итак, Spring Boot подхватывает аннотацию @Bean для LocalContainerEntityManagerFactoryBean, но не создает экземпляры EntityManagerFactory и не подбирает аннотацию @Bean для PlatformTransactionManager.

--- Редактируйте 3 ---

Я установил @Autowired option требуется = 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'
Как создать компоненты прежде всего? Казалось бы, это решило проблему.

--- Редактировать 4 ---

Благодаря совету @RobertNiestroj я добавил @Lazy в аннотации @Autowired, из-за чего они инициализируются после репозиториев then.

Но теперь появляется другая ошибка:

Код: Выделить всё

java.lang.IllegalArgumentException: interface com.mycompany.schema.domain_A.repository.ARepository is not visible from class loader
Я также должен упомянуть, что это приложение построено на основе модулей Maven:
- Модуль схемы (конфигурация JPA, репозитории и классы сущностей)
- Основной модуль (конфигурация приложения и классы свойств)
- [Другие модули, использующие ядро ​​и схему]
- Главный модуль (класс приложения Spring-Boot)

Подробнее здесь: https://stackoverflow.com/questions/537 ... atasources
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»