We can inject spring ApplicationContext as a bean into any bean. By doing so, we are effectively making our bean ApplicationContext aware. Our bean then programmatically can retrieve other beans by calling ApplicationContext.getBean() or retrieve any resources by calling applicationContext#getResource()
Using this approach, we can solve the problem of injecting a prototype bean into singleton bean.
We can inject ApplicationContext as bean using @Autowire annotation (this example) or by implementing spring ApplicationContextAware interface (next example).
Example
Prototype bean
package com.logicbig.example;
import java.time.LocalDateTime;
public class MyPrototypeBean {
private String dateTimeString = LocalDateTime.now().toString();
public String getDateTime() {
return dateTimeString;
}
}
Singleton bean having ApplicationContext injected
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
public class MySingletonBean {
@Autowired
private ApplicationContext applicationContext;
public void showMessage(){
MyPrototypeBean bean = applicationContext.getBean(MyPrototypeBean.class);
System.out.println("Hi, the time is "+bean.getDateTime());
}
}
Main class
package com.logicbig.example;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public MyPrototypeBean prototypeBean() {
return new MyPrototypeBean();
}
@Bean
public MySingletonBean singletonBean() {
return new MySingletonBean();
}
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
MySingletonBean bean = context.getBean(MySingletonBean.class);
bean.showMessage();
Thread.sleep(1000);
bean = context.getBean(MySingletonBean.class);
bean.showMessage();
}
}
OutputHi, the time is 2021-06-12T00:13:04.151 Hi, the time is 2021-06-12T00:13:05.171
Disadvantage of Injecting ApplicationContext
Injecting ApplicationContext, couples the application code to Spring API. Secondly, it does not follow the Inversion of Control principle as we are not letting Spring to inject the dependencies but we are asking the container to give us the dependencies. In some situation this capability might be useful, e.g. some bean taking care of some sort of integration to some other framework etc. However, in general we should avoid this approach for fixing narrower scoped bean injection problem.
Example ProjectDependencies and Technologies Used: - spring-context 6.1.2 (Spring Context)
Version Compatibility: 3.2.3.RELEASE - 6.1.2 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 17
- Maven 3.8.1
|