J'ai un projet avec 3 DataSources différentes. Il fonctionne très bien si le projet est exécuté à partir avec le printemps-boot: exécuter uniquement avec ces dépendances:L'ajout de spring-boot-starter-web aux dépendances casse plusieurs sources de données
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>RELEASE</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-web</artifactId>-->
<!--</dependency>-->
Voici une source de données, ils sont tous à peu près les mêmes, que la modification des informations de noms de haricots et base de données
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "emfIntranet", transactionManagerRef = "tmIntranet", basePackages = {"com.vnt.intranet.repositories"})
@ConfigurationProperties(prefix = "databases.sistemas")
public class IntranetPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Primary
@Bean(name = "dsIntranet")
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
private EclipseLinkJpaVendorAdapter getEclipseLinkJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.PostgreSQLPlatform");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Primary
@Bean(name = "emfIntranet")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getEclipseLinkJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("com.vnt.intranet.entities");
factoryBean.setPersistenceUnitName("intranet");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE/FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Primary
@Bean(name = "tmIntranet")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
Je peux accéder à toutes les sources de données sans problème ... L'une d'entre elles est annotée avec @Primary.
Mais si je décommenter la dépendance printemps-boot-démarreur-web, il se brise et il me donne:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: more than one 'primary' bean found among candidates: [emfIntranet, entityManagerFactory, emfMkRadius, emfMkData]
Je suis en train de convertir à un projet web sans succès ...
Des idées?
EDIT Ajout d'autres classes pour plus de clarté:
MkDataPersistence.class
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "emfMkData", transactionManagerRef = "tmMkData", basePackages = {"org.example.mkdata.repositories"})
@ConfigurationProperties(prefix = "databases.mkdata")
public class MkDataPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Bean(name = "dsMkData")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
@Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Bean(name = "emfMkData")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkdata.entities");
factoryBean.setPersistenceUnitName("mkdata");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE/FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(name = "tmMkData")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
MkRadiusPersistence.class
@Configuration
@EnableTransactionManagement()
@EnableJpaRepositories(entityManagerFactoryRef = "emfMkRadius", transactionManagerRef = "tmMkRadius", basePackages = {"org.example.mkradius.repositories"})
@ConfigurationProperties(prefix = "databases.mkradius")
public class MkRadiusPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Bean(name = "dsMkRadius")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
@Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Bean(name = "emfMkRadius")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkradius.entities");
factoryBean.setPersistenceUnitName("mkradius");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE/FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(name = "tmMkRadius")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
EDIT 2
Application.class
@Configuration
@ComponentScan(basePackages = { "org.example.startup" })
@EnableAutoConfiguration
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
CableRouteRepository cableRouteRepository;
@Autowired
CityRepository cityRepository;
@Autowired
RadAcctRepository radAcctRepository;
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.showBanner(false)
.sources(Application.class)
.run(args);
Application app = context.getBean(Application.class);
// for (String bean: context.getBeanDefinitionNames()) {
// logger.info(bean);
// }
app.start();
}
private void start() {
logger.info("Application.start()");
logger.info("{}", cableRouteRepository.findAll());
logger.info("{}", cityRepository.findAll());
logger.info("{}", radAcctRepository.findTest());
}
}
C'est la classe de démarrage ... J'ai imprimé tous les dépôts comme un test (chaque référentiel est ici sur un autre DataSource) ... Ils fonctionnent très bien tant que je ne suis pas avoir printemps-starter-web sur le classpath.
EDIT 3
Github repo https://github.com/mtrojahn/test-multiple-databases
J'espère que je l'ai fait droit ... Je ne ai jamais vraiment travaillé avec Github :)
EDIT 4
Github mis à jour correctement avec le code défaillant.
Pour rappel, si le soufflet de dépendance est commenté, le code fonctionne:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Et si la dépendance ci-dessus est décommentée mais le soufflet de code est modifié dans le IntranetPersistence.classe de:
@Primary
@Bean(name = "emfIntranet")
à
@Primary
@Bean(name = "entityManagerFactory")
Il remplace le haricot par défaut et commence à échouer avec:
Caused by: java.lang.IllegalArgumentException: Not an managed type: class org.example.intranet.entities.CableRoute
Où sont '' emfMkRadius' et emfMkData' déclaré? Je peux voir que 'emfIntranet' est' @ Primary ', est l'un des deux autres aussi? –
Je vais éditer avec eux, mais ils sont à peu près les mêmes, d'où la raison pour laquelle je ne les ai pas tous postés. –
Le bean 'entityManagerFactory' de Spring Boot est' @ Primary' mais il aurait dû être désactivé par l'un de vos beans 'EntityManagerFactory' car sa création est conditionnelle à ce qu'il ne soit pas un bean' EntityManagerFactory' dans le contexte. A quoi ressemble votre classe principale? Vous référez-vous directement à l'une des classes de configuration automatique de Boot? –