2015-10-16 73 views
0

我有一個包含3個不同DataSources的項目。如果該項目是由彈簧啓動運行它正常工作:這些依賴關係只能運行:將spring-boot-starter-web添加到依賴關係會中斷多個數據源

<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>--> 

這裏有一個數據源,他們都是大同小異的,只是改變bean的名字和數據庫信息

@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; 
    } 
} 

我可以訪問所有數據源,沒有問題...其中一個是用@Primary註釋的。

但是,如果我去掉彈簧引導啓動,網絡依賴它打破它,並給了我:

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] 

我試圖將其轉換爲沒有成功的web項目...

有什麼建議嗎?

EDIT 添加其他類爲清楚起見:

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; 
    } 
} 

編輯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()); 
    } 


} 

這是啓動類......我每一張打印的存儲庫作爲測試(這裏的每個庫是在不同的數據源)。他們只要我不工作得很好在classpath上有spring-starter-web。

編輯3

GitHub庫 https://github.com/mtrojahn/test-multiple-databases

我希望我所做的是正確的......我從來沒有真正與Github上:)

EDIT 4

Github上工作用失敗的代碼正確更新。

在此提醒,如果依賴波紋管被註釋掉,代碼工作:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency> 

如果上面的依賴是註釋掉但代碼波紋管在IntranetPersistence改變。從類:

@Primary 
@Bean(name = "emfIntranet") 

@Primary 
@Bean(name = "entityManagerFactory") 

它覆蓋默認的bean,並開始失敗:

Caused by: java.lang.IllegalArgumentException: Not an managed type: class org.example.intranet.entities.CableRoute 
+0

哪裏'emfMkRadius'和'emfMkData'申報?我可以看到'emfIntranet'是'@ Primary',是另外兩個之一嗎? –

+0

我會和他們一起編輯,但他們幾乎是一樣的,所以我沒有發佈他們。 –

+0

Spring Boot的'entityManagerFactory' bean是'@ Primary',但它應該已被任何一個EntityManagerFactory bean關閉,因爲它的創建條件是它們在上下文中不是EntityManagerFactory bean。你的主課是什麼樣的?你是否直接引用任何Boot的自動配置類? –

回答

1

你受着春天啓動的行爲1.2的JPA自動配置。如果有用戶定義的LocalContainerEntityManagerFactoryBean,它只會關閉創建自己的entityManagerFactory bean。您正在使用LocalContainerEntityManagerFactoryBean,但您自己卻打電話afterPropertiesSetgetObject,而不是讓容器爲您做。這使得上下文將多個@PrimaryEntityManagerFactory豆。這已經是improved in Spring Boot 1.3,因此用戶聲明的EntityManagerFactory bean也將關閉自動配置。

這會在嘗試創建openEntityManagerInViewInterceptor時導致問題,因爲它需要EntityManagerFactory,並且上下文無法知道它應該選擇兩個@Primary bean。

有幾種方法可以繼續。您可以更新您的配置以定義類型爲LocalContainerEntityManagerFactoryBean s的bean,而不是EntityManagerFactory。另一種方法是通過添加禁用以下到您application.yml攔截的創建:

spring: 
    jpa: 
    open_in_view: false 
+0

是的,這似乎解決它。感謝您的時間和興趣:) –

+0

@Coderdood我已經更新了我的答案,並詳細說明了發生了什麼以及爲什麼。 –

+0

是的,我將我的bean更改爲LocalContainerEntityManagerFactoryBean,它做到了這一點。即使使用spring.jpa.open_in_view = true現在也可以工作。謝謝! –

相關問題