Wiring a Bean with BeanReferenceFactoryBean

By Kenan Sevindik

For some reason or another, you may have more than one bean definition with the same type configured in your application context, and you may want to use only one of them based on some condition or configuration option.

For example, I have two PlatformTransactionManager beans configured in my application context.

<bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
 </bean>

<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

I configure both transaction manager beans in my configuration and expect the developer to choose one that is appropriate for the persistence mechanism used in the application. If they use IBatis or JdbcTemplate and perform database operations with direct JDBC calls, then they will choose jdbcTransactionManager. If they use Hibernate with JPA, then they will be expected to choose jpaTransactionManager instead.

With the above configuration, I have one obvious problem with executing integration tests which extend from Spring’s AbstractTransactionalSpringContextTests class. If bean wiring is AUTOWIRE_BY_TYPE, which is the default, then they will complain that there are more than one bean instances with PlatformTransactionManager in the context. On the other hand, if the bean wiring mode is AUTOWIRE_BY_NAME, then injection won’t be performed as the AbstractTransactionalSpringContextTests class expects a bean with the name transactionManager exactly in the context.

Yes, it is possible to rename one of them as transactionManager and continue with the work. However, this is not a very good solution, as for example, if I rename jdbcTransactionManager to transactionManager then integration tests with JPA codes won’t function properly.

<bean id="transactionManager" class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">
    <property name="targetBeanName">
        <value>${db.transaction.manager.bean}</value>
    </property>
</bean>

I need a more flexible solution. Spring’s BeanReferenceFactoryBean class comes to the rescue here. BeanReferenceFactoryBean exposes another bean instance, configured in the context, according to its targetBeanName property. Developers can provide the targetBeanName property value through db.transaction.manager.bean placeholder, which is replaced with the actual bean name, jdbcTransactionManager or jpaTransactionManager using Spring’s PropertyPlaceholderConfigurer mechanism.

Share: X (Twitter) LinkedIn