Создайте bean-компонент в зависимости от свойства, данного фабричному bean-компоненту

Мне нужно создать bean-компонент источника данных в зависимости от tenantIdentifier для мультитенантности. Я думаю о нестандартном решении, в котором добавление нового арендатора так же просто, как добавление конфигурации в context.xml и свойства арендатора в файле свойств приложения, предоставление API для обновления моего context.xml для загрузки из весенней конфигурации облака и файл свойств.

В настоящее время я застрял в этой ошибке:

No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSourceFactoryBean,defaultDataSource

Проблема в том, что теперь мой фабричный компонент создает компонент, который я хочу создать, но даже базовый компонент также зарегистрирован в spring-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"/>

Мой DataSourceFactoryBean выглядит так:

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

Есть ли способ сообщить моим entityManagerFactory и transactionManager использовать мой factory bean, а не фактический bean-компонент defaultDataSource.


person Pavanraotk    schedule 01.02.2017    source источник


Ответы (1)


Попробуйте добавить свойство primary="true" к <bean id="defaultDataSource" Без этого Spring иногда не удается разрешить один компонент из нескольких (даже с квалификатором)

person StanislavL    schedule 01.02.2017
comment
Ты жжешь! Решил мою проблему. Никогда не знал, что есть праймериз. Intellij не показывал это с помощью Ctrl + Space. - person Pavanraotk; 01.02.2017