Это было непросто, но я нашел причину и решение.
Причина
В основном, проблема заключается в том, что я сам настраиваю LocalContainerEntityManagerFactoryBean
.
Если вы этого не сделаете, Spring Boot будет использовать свои автоконфигурации для создания всего хорошего и хорошего, включая свойства вендора (все, что у вас под spring.jpa.properties
), свойства гибернации (все под spring.jpa.hibernate
), а также применение настроек по умолчанию и настроек, среди который я долго искал HibernateJpaAutoConfiguration
.
Но так как мне нужно было несколько источников данных, я обошел все это и, слушая мои уроки, я сделал ленивое следование.
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource1) {
return builder
.dataSource(dataSource1)
.packages("com.example.demo.one.dto")
.build();
}
Решение
В двух словах
Решение почти простое: делайте все, что будет делать Spring Boot. Только «почти», потому что большинство из этих механизмов полагаются на автоконфигурации (их переопределение - это запах кода, так что это не так) и / или внутренние / защищенные классы (которые вы не можете вызвать напрямую).
Возможная хрупкость?
Это означает, что вам, по сути, нужно скопировать код Spring Boot в свой собственный, возможно, создать некоторую хрупкость в отношении будущих обновлений Spring Boot (или просто, что ваш код не принесет пользы из последних исправлений ошибок / выступлений). Исходя из этого, я не большой поклонник решения, которое я здесь представляю.
Подробное руководство
Бины, от которых вы зависите
Вам нужно будет добавить следующие бины в вашей конфигурации источника данных:
org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties
org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
List<org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer>
Операции для выполнения
Рисуя org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
, я добавил настройщик свойства hibernate.resource.beans.container
. Однако я пропустил политики именования, которые не являются проблемой в нашем проекте.
Это дает мне следующий конструктор и метод:
public DataSource1Config(
JpaProperties jpaProperties,
HibernateProperties hibernateProperties,
ConfigurableListableBeanFactory beanFactory,
ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers
) {
this.jpaProperties = jpaProperties;
this.hibernateProperties = hibernateProperties;
this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers(
beanFactory,
hibernatePropertiesCustomizers.orderedStream().collect(Collectors.toList())
);
}
private List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomizers(
ConfigurableListableBeanFactory beanFactory,
List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers
) {
List<HibernatePropertiesCustomizer> customizers = new ArrayList<>();
if (ClassUtils.isPresent("org.hibernate.resource.beans.container.spi.BeanContainer",
getClass().getClassLoader())) {
customizers.add((properties) -> properties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory)));
}
customizers.addAll(hibernatePropertiesCustomizers);
return customizers;
}
Затем, опираясь на org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration
, я загрузил свойства продавца. Здесь я снова пропустил некоторые автоматические настройки c, на которые вы можете посмотреть (JpaBaseConfiguration#customizeVendorProperties(Map)
и их реализация в подклассах).
private Map<String, Object> getVendorProperties() {
return new LinkedHashMap<>(
this.hibernateProperties
.determineHibernateProperties(jpaProperties.getProperties(),
new HibernateSettings()
// Spring Boot's HibernateDefaultDdlAutoProvider is not available here
.hibernatePropertiesCustomizers(this.hibernatePropertiesCustomizers)
)
);
}
Полный класс конфигурации
Так же, как для справки, я дам вам полный класс конфигурации, как только применил изменения, описанные выше.
package com.example.demo.config;
import org.hibernate.cfg.AvailableSettings;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.SpringBeanContainer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.ClassUtils;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.example.demo.one.repository",
entityManagerFactoryRef = "dataSource1EntityManagerFactory",
transactionManagerRef = "TransactionManager1"
)
public class DataSource1Config {
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
private final List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;
public DataSource1Config(
JpaProperties jpaProperties,
HibernateProperties hibernateProperties,
ConfigurableListableBeanFactory beanFactory,
ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers
) {
this.jpaProperties = jpaProperties;
this.hibernateProperties = hibernateProperties;
this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers(
beanFactory,
hibernatePropertiesCustomizers.orderedStream().collect(Collectors.toList())
);
}
private List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomizers(
ConfigurableListableBeanFactory beanFactory,
List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers
) {
List<HibernatePropertiesCustomizer> customizers = new ArrayList<>();
if (ClassUtils.isPresent("org.hibernate.resource.beans.container.spi.BeanContainer",
getClass().getClassLoader())) {
customizers.add((properties) -> properties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory)));
}
customizers.addAll(hibernatePropertiesCustomizers);
return customizers;
}
@Bean
@Primary
@ConfigurationProperties(prefix = "datasource.lib")
public DataSourceProperties dataSource1Properties() {
return new DataSourceProperties();
}
@Bean
@Primary
public DataSource dataSource1(DataSourceProperties dataSource1Properties) {
return dataSource1Properties.initializeDataSourceBuilder().build();
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory(EntityManagerFactoryBuilder factoryBuilder, DataSource dataSource1) {
final Map<String, Object> vendorProperties = getVendorProperties();
return factoryBuilder
.dataSource(dataSource1)
.packages("com.example.demo.one.dto")
.properties(vendorProperties)
.build();
}
@Bean
@Primary
public PlatformTransactionManager transactionManager1(EntityManagerFactory dataSource1EntityManagerFactory) {
return new JpaTransactionManager(dataSource1EntityManagerFactory);
}
private Map<String, Object> getVendorProperties() {
return new LinkedHashMap<>(
this.hibernateProperties
.determineHibernateProperties(jpaProperties.getProperties(),
new HibernateSettings()
// Spring Boot's HibernateDefaultDdlAutoProvider is not available here
.hibernatePropertiesCustomizers(this.hibernatePropertiesCustomizers)
)
);
}
}