Welcome

Wiring a Bean with BeanReferenceFactoryBean

For some reason or other you may have more than one bean definition with same type configured in you 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 which is appropriate to the persistency mechanism used in the application. If he uses IBatis, or JdbcTemplate and perform database operations with direct JDBC calls then, he will choose jdbcTransactionManager. If he uses Hibernate with JPA, then he will be expected to choose jpaTransactionManager instead.

With 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 by default, then they will complain that there are more than one bean instance 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 AbstractTransactionalSpringContextTests class expects a bean with name transactionManager exactly in the context.

Yes, it is possible to rename one of them as transactionManager and continue to 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.

I need a more flexible solution. Spring’s BeanReferenceFactoryBean class comes to rescue here. BeanReferenceFactoryBean expose another bean instance, configured in the context, according to its targetBeanName property.

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

Developers can provide targetBeanName property value through db.transaction.manager.bean placeholder which is replaced with actual bean name, jdbcTransactionManager or jpaTransactionManager using Spring’s PropertyPlaceholderConfigurer mechanism.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.