Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a Pre-constructed Bean to a Spring Application Context

Tags:

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?

like image 989
Adam Paynter Avatar asked Jan 30 '09 18:01

Adam Paynter


People also ask

Does application context pre instantiate beans?

The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup.

How do you get a bean in Spring boot application context?

Spring Boot injects the application context into the parameter of the setApplicationContext() method, where we get the Id of the Spring application. (The Id here is the name of the application.) In the Application , we create a bean, call its method and set up the Spring Boot application.


2 Answers

I have been in the exact same situation. As nobody proposed my solution (and I think my solution is more elegant), I will add it here for future generations :-)

The solution consists of two steps:

  1. create parent ApplicationContext and register your existing bean in it.
  2. create child ApplicationContext (pass in parent context) and load beans from XML file

Step #1:

//create parent BeanFactory DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory(); //register your pre-fabricated object in it parentBeanFactory.registerSingleton("dataSource", dataSource); //wrap BeanFactory inside ApplicationContext GenericApplicationContext parentContext =          new GenericApplicationContext(parentBeanFactory); parentContext.refresh(); //as suggested "itzgeoff", to overcome a warning about events 

Step #2:

//create your "child" ApplicationContext that contains the beans from "beans.xml" //note that we are passing previously made parent ApplicationContext as parent ApplicationContext context = new ClassPathXmlApplicationContext(         new String[] {"beans.xml"}, parentContext); 
like image 62
Neeme Praks Avatar answered Sep 19 '22 14:09

Neeme Praks


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!

like image 29
Adam Paynter Avatar answered Sep 17 '22 14:09

Adam Paynter