In Spring, the lookup method injection is the ability of the container to override methods on container-managed beans and return a container-managed bean as lookup result specified as method return type.
1. Inspiration for Method Injection
Method injection can be seen as Spring container overriding a container-managed bean class and then overriding its one specific method. The container can insert any specific behavior through this overridden method.
The primary inspiration for this design was the classical scoped bean injection problem. In this problem, we want to inject a prototype-scoped bean dependency into a singleton-scoped bean.
Note that SingletonBean and PrototypeBean, both are container-managed beans.
@Component
public class SingletonBean {
@Autowired
private PrototypeBean prototypeBean;
}
A typical solution to the above problem is using the ApplicationContext to get a new instance of PrototypeBean inside a getter method in class SingletonBean.
@Component
public class SingletonBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public PrototypeBean getPrototypeBean() {
return applicationContext.getBean(PrototypeBean.class);
}
}
2. Method Injection via @Lookup
In the above solution using the ApplicationContext, we can see the followings:
- It will be almost the same code to solve this problem everytime.
- The ApplicationContext and PrototypeBean, are both managed by the Spring container.
So it makes complete sense to abstract the logic at the framework layer and provides a generic shortcut to apply the solution quickly. The @Lookup
annotation serves exactly this purpose. The @Lookup
annotation indicates ‘lookup’ methods to be overridden by the container to redirect them back to the BeanFactory for a getBean call.
We can rewrite the previous solution using @Lookup as follows. Both solutions do the exact same thing. They return a new instance of PrototypeBean when the getter method is invoked. The container uses reflection (using CGLIB) to invoke the getter method and override its definition.
@Component
public class SingletonBean {
@Lookup
public PrototypeBean getPrototypeBean() {
return null;
}
}
Please note that @Lookup is the Java equivalent of the XML element ‘lookup-method’.
<bean id="prototypeBean" class="com.app.PrototypeBean" />
<bean id="singletonBean" class="com.app.SingletonBean">
<lookup-method name="getPrototypeBean" bean="prototypeBean"/>
</bean>
It is worth mentioning that the body of lookup method does not matter because it is never executed. If the method is abstract, the dynamically-generated subclass implements the method, else subclass overrides the concrete method defined in the original class.
3. When does @Lookup not Work?
As the @Lookup method-based method injection requires the beans to be container-managed, the container should be able to subclass the beans. For this reason, the annotated method must not be private, final or static so the method can be overridden in the subclass.
Also, note that lookup methods would not work on beans returned from @Bean methods in configuration classes. In such a case, consider bean injection using @Inject Provider<PrototypeBean>.
4. Conclusion
In this Spring tutorial, we learned what is method injection, how it is implemented in a Spring container and how it solved the scoped bean injection problem. We also learned about the @Lookup annotation with examples, and when it will not work in the application code.
Happy Learning !!
Comments