Adam Paynter Adam Paynter - 4 months ago 19
Java Question

Adding a Pre-constructed Bean to a Spring Application Context

I am writing a class that implements the following method:

public void run(javax.sql.DataSource dataSource);


Within this method, I wish to construct a Spring application context using a configuration file similar to the following:

<bean id="dataSource" abstract="true" />

<bean id="dao" class="my.Dao">
<property name="dataSource" ref="dataSource" />
</bean>


Is it possible to force Spring to use the DataSource object passed to my method wherever the "dataSource" bean is referenced in the configuration file?

Answer

I discovered two Spring interfaces can be used to implement what I need. The BeanNameAware interface allows Spring to tell an object its name within an application context by calling the setBeanName(String) method. The FactoryBean interface tells Spring to not use the object itself, but rather the object returned when the getObject() method is invoked. Put them together and you get:

public class PlaceholderBean implements BeanNameAware, FactoryBean {

    public static Map<String, Object> beansByName = new HashMap<String, Object>();

    private String beanName;

    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    @Override
    public Object getObject() {
        return beansByName.get(beanName);
    }

    @Override
    public Class<?> getObjectType() {
        return beansByName.get(beanName).getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}

The bean definition is now reduced to:

<bean id="dataSource" class="PlaceholderBean" />

The placeholder receives its value before creating the application context.

public void run(DataSource externalDataSource) {
    PlaceholderBean.beansByName.put("dataSource", externalDataSource);
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    assert externalDataSource == context.getBean("dataSource");
}

Things appear to be working successfully!