深入理解Spring中的Lookup(方法注入)
前言
本文主要给大家介绍了关于spring中lookup(方法注入)的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:
在使用spring时,可能会遇到这种情况:一个单例的bean依赖另一个非单例的bean。如果简单的使用自动装配来注入依赖,就可能会出现一些问题,如下所示:
单例的class a
@component public class classa { @autowired private classb classb; public void printclass() { system.out.println("this is class a: " + this); classb.printclass(); } }
非单例的class b
@component @scope(value = scope_prototype) public class classb { public void printclass() { system.out.println("this is class b: " + this); } }
这里class a采用了默认的单例scope,并依赖于class b, 而class b的scope是prototype,因此不是单例的,这时候跑个测试就看出这样写的问题:
@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(); } } }
输出的结果是:
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
可以看到,两个类的hash code在三次输出中都是一样。class a的值不变是可以理解的,因为它是单例的,但是class b的scope是prototype却也保持hash code不变,似乎也成了单例?
产生这种的情况的原因是,class a的scope是默认的singleton,因此context只会创建class a的bean一次,所以也就只有一次注入依赖的机会,容器也就无法每次给class a提供一个新的class b。
不那么好的解决方案
要解决上述问题,可以对class a做一些修改,让它实现applicationcontextaware。
@component public 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; } }
这样就能够在每次需要到class b的时候手动去context里找到新的bean。再跑一次测试后得到了以下输出:
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
可以看到class a的hash code在三次输出中保持不变,而class b的却每次都不同,说明问题得到了解决,每次调用时用到的都是新的实例。
但是这样的写法就和spring强耦合在一起了,spring提供了另外一种方法来降低侵入性。
@lookup
spring提供了一个名为@lookup的注解,这是一个作用在方法上的注解,被其标注的方法会被重写,然后根据其返回值的类型,容器调用beanfactory的getbean()方法来返回一个bean。
@component public class classa { public void printclass() { system.out.println("this is class a: " + this); getclassb().printclass(); } @lookup public classb getclassb() { return null; } }
可以发现简洁了很多,而且不再和spring强耦合,再次运行测试依然可以得到正确的输出。
被标注的方法的返回值不再重要,因为容器会动态生成一个子类然后将这个被注解的方法重写/实现,最终调用的是子类的方法。
使用的@lookup的方法需要符合如下的签名:
<public|protected> [abstract] <return-type> themethodname(no-arguments);
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。