I need to get prototype class from singleton. I found that method injection is the way to go, but I don't really know how to use spring @Lookup annotation.
I'm new to dependency-injection, and I chose to go with annotation configuration, so I would like to continue in that direction.
I found out that @Lookup annotation was added only recently (https://spring.io/blog/2014/09/04/spring-framework-4-1-ga-is-here), but I cannot find anywhere how to use it.
So, here is simplified example
Configuration class:
@Configuration
@Lazy
public class ApplicationConfiguration implements ApplicationConfigurationInterface {
@Bean
public MyClass1 myClass1() {
return new ContentHolderTabPaneController();
}
@Bean
@Scope("prototype")
public MyClass2 myClass2() {
return new SidebarQuickMenuController();
}
}
And here is class example:
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
public MyClass2 myClass2(){
}
}
How do I do that with @Lookup annotation?
Why @Lookup? A method annotated with @Lookup tells Spring to return an instance of the method's return type when we invoke it. Essentially, Spring will override our annotated method and use our method's return type and parameters as arguments to BeanFactory#getBean.
To put it in simple words, lookup method injection is the process to override a Spring bean at the runtime. The constructor and property are the most common used dependency injection methods. Both the options happen during the initialization of the Bean.
Dependency lookup is when the object itself is trying to find a dependency, such as: ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml"); MyBean bean = applicationContext.getBean("myBean")
The @Resource annotation in spring performs the autowiring functionality. This annotation follows the autowire=byName semantics in the XML based configuration i.e. it takes the name attribute for the injection. Below snippet shows how to use this annotation. This annotation takes an optional name argument.
Before applying @Lookup
annotation to your public MyClass2 myClass2()
method, read this in @Lookup's Javadoc:
the container will generate runtime subclasses of the method's containing class via CGLIB, which is why such lookup methods can only work on beans that the container instantiates through regular constructors (i.e. lookup methods cannot get replaced on beans returned from factory methods where we can't dynamically provide a subclass for them).
So remove the following factory method style bean declaration from ApplicationConfiguration
:
@Bean
public MyClass1 myClass1() {
return new ContentHolderTabPaneController();
}
and add @Component
annotation to let Spring instantiate the bean (also add the @Lookup
annotation to the method):
@Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
@Lookup
public MyClass2 myClass2(){
return null; // This implementation will be overridden by dynamically generated subclass
}
}
Now get myClass1
bean out of context, and its myClass2
method should have been replaced/overridden to get a new prototype bean each time.
Update:
It's not hard to implement the @Lookup
annotated method (the "lookup method"). Without @Lookup
and keeping your configuration class unchanged, now MyClass1
looks like (in fact Spring generates a similar implementation in a subclass if @Lookup
were used):
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
@Autowired
private ApplicationContext applicationContext;
public MyClass2 myClass2() {
return applicationContext.getBean(MyClass2.class);
}
}
Spring injects the ApplicationContext
for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With