Preface
This article mainly introduces the relevant content about Lookup (method injection) in Spring. It is shared for your reference and learning. I won’t say much below. Let’s take a look at the detailed introduction together:
This may happen when using Spring: One singleton bean depends on another non-singleton bean. If you simply use auto-assembly to inject dependencies, some problems may arise, as shown below:
Class A for singleton
@Componentpublic class ClassA { @Autowired private ClassB classB; public void printClass() { System.out.println("This is Class A: " + this); classB.printClass(); }}Class B for non-single
@Component@Scope(value = SCOPE_PROTOTYPE)public class ClassB { public void printClass() { System.out.println("This is Class B: " + this); }} Here Class A adopts the default singleton scope and relies on Class B. The scope of Class B is prototype, so it is not a singleton. At this time, you can see the problem of writing like this after running a test:
@RunWith(SpringRunner.class)@ContextConfiguration(classes = {ClassA.class, ClassB.class})public class MyTest { @Autowired private ClassA classA; @Test public void simpleTest() { for (int i = 0; i < 3; i++) { classA.printClass(); } }}The output result is:
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
As you can see, the Hash Code of both classes is the same in the three outputs. It is understandable that the value of Class A remains unchanged because it is a singleton, but the scope of Class B is a prototype but also keeps the Hash Code unchanged, which seems to have become a singleton?
The reason for this situation is that Class A's scope is the default singleton, so the Context will only create Class A's bean once, so there is only one chance to inject dependencies, and the container cannot provide Class A with a new Class B every time.
Not so good solution
To solve the above problem, you can make some modifications to Class A to implement ApplicationContextAware.
@Componentpublic class ClassA implements ApplicationContextAware { private ApplicationContext applicationContext; public void printClass() { System.out.println("This is Class A: " + this); getClassB().printClass(); } public ClassB getClassB() { return applicationContext.getBean(ClassB.class); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}This way, you can manually find a new bean in the Context every time you need to go to Class B. After running another test, I got the following output:
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@31206beb
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3e77a1ed
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3ffcd140
You can see that the Hash Code of Class A remains unchanged in the three outputs, while the Class B is different every time, which shows that the problem has been solved and the new instance is used every time it is called.
However, this writing method is strongly coupled with Spring, and Spring provides another way to reduce invasiveness.
@Lookup
Spring provides an annotation called @Lookup, which is an annotation that works on the method. The method marked by it will be overridden. Then, according to the type of its return value, the container calls the getBean() method of the BeanFactory to return a bean.
@Componentpublic class ClassA { public void printClass() { System.out.println("This is Class A: " + this); getClassB().printClass(); } @Lookup public ClassB getClassB() { return null; }} It can be found that it is much simpler and no longer strongly coupled with Spring. Running the test again can still get the correct output.
The return value of the annotated method is no longer important, because the container will dynamically generate a subclass and then rewrite/implement the annotated method, and the subclass method is finally called.
The @Lookup method used must comply with the following signature:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.