If same scoped beans are wired together there's no problem. For example a singleton bean A injected into another singleton bean B. But if the bean A has the shorted-liver scope say prototype scope then there's a problem.
When injecting a shorter-lived scoped bean into a longer-lived scoped bean (for example, injecting a prototype bean into a single bean or an HTTP Session-scoped bean into singleton bean), then we may want to get a new instance of shorter-lived scoped bean multiple times during the lifespan of longer-lived scoped bean.
To understand the problem let's see an example. We are going to have two beans MyPrototypeBean, scoped as prototype and MySingletonBean, scoped as singleton. We will inject the prototype bean into the singleton bean. We will also access MySingletonBean via method call context#getBean(MySingletonBean.class) multiple times. We are expecting (per prototype specifications) that a new prototype bean will be created and be injected into MySingletonBean every time.
Example
Creating a prototype bean
package com.logicbig.example;
import java.time.LocalDateTime;
public class MyPrototypeBean {
private String dateTimeString = LocalDateTime.now().toString();
public String getDateTime() {
return dateTimeString;
}
}
Creating a singleton bean and injecting the prototype bean in it
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
public class MySingletonBean {
@Autowired
private MyPrototypeBean prototypeBean;
public void showMessage(){
System.out.println("Hi, the time is "+prototypeBean.getDateTime());
}
}
Declaring beans via @Bean and initiating app
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 2025-10-28T16:55:34.661962200 Hi, the time is 2025-10-28T16:55:34.661962200
In above output we are expecting MySingletonBean would print two different time, with approximately one sec difference.
The problem is: spring container creates the singleton bean MySingletonBean only once, and thus only gets one opportunity to inject the dependencies into it. The container cannot provide MySingletonBean with a new instance of MyPrototypeBean every time one is needed.
Solution to the problem
Following are the solutions to the above problems
- Inject
ApplicationContext bean into MySingletonBean to get instance of MyPrototypeBean, whenever we need it (example).
- Lookup method injection. This approach involves in dynamic bytecode generation (example).
- Using Scoped Proxy. (example here and here).
- Using JSR 330
Provider<T> injected by Spring (example).
- Injecting Spring's
ObjectProvider<T> (example).
- By using Java 8 Functions (example).
Example ProjectDependencies and Technologies Used: - spring-context 6.2.13 (Spring Context)
Version Compatibility: 3.2.3.RELEASE - 6.2.13 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 25
- Maven 3.9.11
|