Spring lookup method injection is the process of dynamically overriding a registered bean method.
The bean method should be annotated with @Lookup.
Spring returns the lookup result matched by the method's return type.
@Component
public class MySingletonBean {
public void showMessage(){
MyPrototypeBean bean = getPrototypeBean();
//each time getPrototypeBean() call
//will return new instance
}
@Lookup
public MyPrototypeBean getPrototypeBean(){
//spring will override this method
return null;
}
}
In above example the method getPrototypeBean is returning null. That doesn't matter, because this method will actually be overridden by spring dynamically. Spring uses CGLIB library to do so.
The dynamically generated code will look for the target bean in the application context. Something like this:
...
public MyPrototypeBean getPrototypeBean(){
return applicationContext.getBean(MyPrototypeBean.class);
}
...
This is the one of the solution for a prototype bean being injected in singleton bean, as described in the previous tutorials.
For dynamic code generation to work, we have to follow these conditions on the bean class :
- The bean class cannot be final.
- The method annotated with
@Lookup , cannot be private , static or final
- The factory approach of JavaConfig doesn't work i.e. a factory method annotated with
@Bean and returning a manually created instance of the bean doesn't work. Since the container is not in charge of creating the instance, therefore it cannot create a runtime-generated subclass on the fly. So we have to use component scanning approach as described here
Complete Example
Prototype bean
package com.logicbig.example;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
public class MyPrototypeBean {
private String dateTimeString = LocalDateTime.now().toString();
public String getDateTime() {
return dateTimeString;
}
}
Singleton bean using @Lookup
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;
@Component
public class MySingletonBean {
public void showMessage(){
MyPrototypeBean bean = getPrototypeBean();
System.out.println("Hi, the time is "+bean.getDateTime());
}
@Lookup
public MyPrototypeBean getPrototypeBean(){
//spring will override this method
return null;
}
}
Main class
package com.logicbig.example;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(basePackageClasses = MySingletonBean.class)
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public MyPrototypeBean prototypeBean() {
return new MyPrototypeBean();
}
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-05-05T01:48:06.776 Hi, the time is 2021-05-05T01:48:07.787
Example ProjectDependencies and Technologies Used: - spring-context 6.1.2 (Spring Context)
Version Compatibility: 4.1.0.RELEASE - 6.1.2 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 17
- Maven 3.8.1
|