I have to create a datasource bean depending on the tenantIdentifier for multi-tenancy. I'm thinking out of the box solution where adding a new tenant is as simple as adding the configuration in context.xml and the tenant properties in the application properties file, expose an API to refresh my context.xml to load from spring cloud config and the properties file.
Currently, I'm stuck at this error:
No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSourceFactoryBean,defaultDataSource
The problem is, now my factory bean is creating the bean that I want it to create, but even the underlying bean is also registered in spring-context. This is causing the above problem.
This is my context xml:
<bean id="dataSourceFactoryBean" class="com.comviva.mfs.txn.util.DataSourceFactoryBean" scope="prototype">
<property name="tenantIdentifier" value="defaultDataSource"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="defaultDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="txnOracle"/>
<property name="registerMbeans" value="false"/>
<property name="dataSourceClassName" value="oracle.jdbc.pool.OracleDataSource"/>
<property name="maximumPoolSize" value="${mobiquity.database.connection.pool.maximum.pool.size}"/>
<property name="minimumIdle" value="${mobiquity.database.connection.pool.minimum.pool.size}"/>
<property name="connectionTimeout" value="${mobiquity.database.connection.pool.connection.timeout}"/>
<property name="idleTimeout" value="${mobiquity.database.connection.pool.idle.timeout}"/>
<property name="maxLifetime" value="${mobiquity.database.connection.pool.max.lifetime}"/>
<property name="dataSourceProperties">
<props>
<prop key="url">${mobiquity.database.url}</prop>
<prop key="user">${mobiquity.database.username}</prop>
<prop key="password">${mobiquity.database.password}</prop>
<prop key="implicitCachingEnabled">${mobiquity.database.implicitCachingEnabled}</prop>
<prop key="maxStatements">${mobiquity.database.maxStatements}</prop>
</props>
</property>
<property name="metricRegistry" ref="platformCommonMetricRegistry"/>
<property name="healthCheckRegistry" ref="platformCommonHealthCheckRegistry"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="NewOracle"/>
<property name="dataSource" ref="dataSourceFactoryBean"/>
<property name="jpaDialect" ref="jpaDialect"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="showSql" value="${show.sql}"/>
<!--<property name="generateDdl" value="true"/>-->
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSourceFactoryBean"/>
<property name="defaultTimeout" value="${default.timeout}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
My DataSourceFactoryBean is like this:
public class DataSourceFactoryBean extends AbstractFactoryBean<DataSource> {
@Autowired
ApplicationContext applicationContext;
private String tenantIdentifier;
public String getTenantIdentifier() {
return tenantIdentifier;
}
public void setTenantIdentifier(String tenantIdentifier) {
this.tenantIdentifier = tenantIdentifier;
}
@Override
public Class<DataSource> getObjectType() {
return DataSource.class;
}
@Override
protected DataSource createInstance() throws Exception {
DataSource dataSource = (DataSource) applicationContext.getBean(tenantIdentifier);
return dataSource;
}
Is there any way for me to tell my entityManagerFactory and transactionManager to use my factory bean and not the actual defaultDataSource bean.