v一、前言
本文章所講并沒有基于aspectj,而是直接通過cglib以及proxyfactorybean去創(chuàng)建代理bean。通過下面的例子,可以看出cglib方式創(chuàng)建的代理bean和proxyfactorybean創(chuàng)建的代理bean的區(qū)別。
v二、基本測試代碼
測試實體類,在bpp中創(chuàng)建bpptestdepbean類型的代理bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@component public static class bpptestbean { @autowired private bpptestdepbean depbean; public void test1() { depbean.testdep(); } public void test2() { depbean.testdep(); } @testmethod public void test3() { depbean.testdep(); } } @component public static class bpptestdepbean { public void testdep() { system.out.println( "hehe" ); } } @target (elementtype.method) @retention (retentionpolicy.runtime) @documented public @interface testmethod { } |
測試類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@springboottest public class bpptest { @autowired private bpptestbean bpptestbean; @test public void test() { bpptestbean.test1(); bpptestbean.test2(); bpptestbean.test3(); } } |
v三、使用cglib創(chuàng)建代理bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class proxybpp1 implements beanpostprocessor { private static final logger logger = loggerfactory.getlogger(proxybpp1. class ); @override public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception { if (bean instanceof bpptestbean) { enhancer enhancer = new enhancer(); enhancer.setsuperclass(bean.getclass()); //標識spring-generated proxies enhancer.setinterfaces( new class []{springproxy. class }); //設置增強 enhancer.setcallback((methodinterceptor) (target, method, args, methodproxy) -> { if ( "test1" .equals(method.getname())) { logger.info( "proxybpp1 開始執(zhí)行..." ); object result = methodproxy.invokesuper(target, args); logger.info( "proxybpp1 結束執(zhí)行..." ); return result; } return method.invoke(target, args); }); return enhancer.create(); } return bean; } } |
主要是代理 bpptestbean的test1方法。其實這種方式創(chuàng)建的代理bean使用問題的,@autowired字段沒有注入進來,所以會有出現(xiàn)npe。methodproxy.invokesuper(target, args)
,這一行代碼是有問題的,targe是代理類對象,而真實的對象是postprocessbeforeinitialization(object bean, string beanname)
中的bean對象,此時bean對象@autowired字段已經注入了。所以可以將methodproxy.invokesuper(target, args)
修改為method.invoke(bean, args)
解決無法注入@autowired字段的問題。
v四、使用proxyfactorybean創(chuàng)建代理bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class proxybpp2 implements beanpostprocessor { private static final logger logger = loggerfactory.getlogger(proxybpp2. class ); @override public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception { if (bean instanceof bpptestbean) { proxyfactorybean pfb = new proxyfactorybean(); pfb.settarget(bean); pfb.setautodetectinterfaces( false ); namematchmethodpointcutadvisor advisor = new namematchmethodpointcutadvisor(); advisor.addmethodname( "test1" ); advisor.setadvice((methodinterceptor) invocation -> { logger.info( "proxybpp2 開始執(zhí)行..." ); object result = invocation.getmethod().invoke(invocation.getthis(), invocation.getarguments()); logger.info( "proxybpp2 結束執(zhí)行..." ); return result; }); pfb.addadvisor(advisor); return pfb.getobject(); } return bean; } } |
使用proxyfactorybean創(chuàng)建代理bean的時候,一定要一個targe對象的。advisor在切入的時候,會逐個執(zhí)行advice。invocation.getthis()
就是在通過proxyfactorybean創(chuàng)建代理bean的時候傳入的target對象。由于target對象就是postprocessbeforeinitialization(object bean, string beanname)
中的bean對象,所以@autowired字段也已經注入進來了。
v五、@autowired注解何時被處理
想必大家都知道@autowired字段的處理也是通過一個bpp,不過這個bpp比我們平常使用的要高級一些,它就是instantiationawarebeanpostprocessor。這個bpp可以實現(xiàn)bean的創(chuàng)建、屬性的注入和解析(比如@autowired、@value、@resource等等),大家可以參考一下commonannotationbeanpostprocessor(處理jsr-250相關注解),autowiredannotationbeanpostprocessor(處理@autowired、@value、@inject相關注解)。
instantiationawarebeanpostprocessor中有一個如下的方法,autowiredannotationbeanpostprocessor就是覆蓋這個方法實現(xiàn)了帶有相關注解屬性的自動注入。
1
2
3
4
5
6
|
@nullable default propertyvalues postprocessproperties(propertyvalues pvs, object bean, string beanname) throws beansexception { return null ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@override public propertyvalues postprocessproperties(propertyvalues pvs, object bean, string beanname) { injectionmetadata metadata = findautowiringmetadata(beanname, bean.getclass(), pvs); try { metadata.inject(bean, beanname, pvs); } catch (beancreationexception ex) { throw ex; } catch (throwable ex) { throw new beancreationexception(beanname, "injection of autowired dependencies failed" , ex); } return pvs; } |
instantiationawarebeanpostprocessor的postprocessproperties方法實在spring abstractautowirecapablebeanfactory的populatebean方法中被調用。在abstractautowirecapablebeanfactory的docreateban中有如下代碼。
1
2
3
4
5
6
|
// initialize the bean instance. object exposedobject = bean;# try { populatebean(beanname, mbd, instancewrapper); exposedobject = initializebean(beanname, exposedobject, mbd); } |
也就是先進行了bean的屬性填充,然后進行bean的初始化工作。initializebean方法中主要做了四件事。
1、invokeawaremethods
2、applybeanpostprocessorsbeforeinitialization
3、invokeinitmethods
4、applybeanpostprocessorsafterinitialization
其中2和4就是分別調用的普通的bpp中的postprocessbeforeinitialization方法和postprocessafterinitialization方法。
這就是為什么在bpp中創(chuàng)建代理bean的時候,對應的目標bean相關的@autowired字段已經注入的原因了。
v六、instantiationawarebeanpostprocessor方式創(chuàng)建動態(tài)代理bean
instantiationawarebeanpostprocessor接口中有個postprocessbeforeinstantiation方法,可以讓我們自己去實例化bean。通過查看abstractautowirecapablebeanfactory,方法調用:createbean方法 -> resolvebeforeinstantiation方法 -> applybeanpostprocessorsbeforeinstantiation方法 ->instantiationawarebeanpostprocessor#postprocessbeforeinstantiation方法,如果最終返回一個非null的實例,那么就不會再執(zhí)行docreatebean方法。這就意味著不會有bean屬性的填充和初始化的流程了,但是可以借助abstractautowirecapablebeanfactory幫助我們實現(xiàn)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public <t> t postprocess(t object) { if (object == null ) { return null ; } t result; try { // 使用容器autowirebeanfactory標準依賴注入方法autowirebean()處理 object對象的依賴注入 this .autowirebeanfactory.autowirebean(object); // 使用容器autowirebeanfactory標準初始化方法initializebean()初始化對象 object result = (t) this .autowirebeanfactory.initializebean(object, object.tostring()); } catch (runtimeexception e) { class <?> type = object.getclass(); throw new runtimeexception( "could not postprocess " + object + " of type " + type, e); } return result; } |
上圖代碼,可以幫組我們實現(xiàn)非spring容器bean自動注入和初始化的功能。使用過spring security同學都知道,內部也是用了這個方式解決對象中的屬性注入問題。如果你閱讀了spring security的源碼,你會發(fā)現(xiàn)很多對象,比如websecurity、providermanager、各個安全filter等,這些對象的創(chuàng)建并不是通過bean定義的形式被容器發(fā)現(xiàn)和注冊進入spring容器的,而是直接new出來的。spring security提供的autowirebeanfactoryobjectpostprocessor這個工具類可以使這些對象具有容器bean同樣的生命周期,也能注入相應的依賴,從而進入準備好被使用的狀態(tài)。
使用cglib在instantiationawarebeanpostprocessor 中創(chuàng)建動態(tài)代理bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class proxybpp3 implements instantiationawarebeanpostprocessor { private static final logger logger = loggerfactory.getlogger(proxybpp3. class ); private final autowirecapablebeanfactory autowirebeanfactory; proxybpp3(autowirecapablebeanfactory autowirebeanfactory) { this .autowirebeanfactory = autowirebeanfactory; } @override public object postprocessbeforeinstantiation( class <?> beanclass, string beanname) throws beansexception { if (beanclass.equals(bppconfig.bpptestbean. class )) { enhancer enhancer = new enhancer(); enhancer.setsuperclass(beanclass); //標識spring-generated proxies enhancer.setinterfaces( new class []{springproxy. class }); //設置增強 enhancer.setcallback((methodinterceptor) (target, method, args, methodproxy) -> { if ( "test1" .equals(method.getname())) { logger.info( "proxybpp3 開始執(zhí)行..." ); object result = methodproxy.invokesuper(target, args); logger.info( "proxybpp3 結束執(zhí)行..." ); return result; } return methodproxy.invokesuper(target, args); }); return this .postprocess(enhancer.create()); } return null ; } ... } |
使用proxyfactorybean在instantiationawarebeanpostprocessor 中創(chuàng)建動態(tài)代理bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class proxybpp4 implements instantiationawarebeanpostprocessor { private static final logger logger = loggerfactory.getlogger(proxybpp4. class ); private final autowirecapablebeanfactory autowirebeanfactory; proxybpp4(autowirecapablebeanfactory autowirebeanfactory) { this .autowirebeanfactory = autowirebeanfactory; } @override public object postprocessbeforeinstantiation( class <?> beanclass, string beanname) throws beansexception { if (beanclass.equals(bppconfig.bpptestbean. class )) { proxyfactorybean pfb = new proxyfactorybean(); pfb.settarget( this .postprocess(beanutils.instantiateclass(beanclass))); pfb.setautodetectinterfaces( false ); namematchmethodpointcutadvisor advisor = new namematchmethodpointcutadvisor(); advisor.addmethodname( "test1" ); advisor.setadvice((methodinterceptor) invocation -> { logger.info( "proxybpp4 開始執(zhí)行..." ); object result = invocation.getmethod().invoke(invocation.getthis(), invocation.getarguments()); logger.info( "proxybpp4 結束執(zhí)行..." ); return result; }); pfb.addadvisor(advisor); return pfb.getobject(); } return null ; } ... } |
上述向兩種方式,注意,實例化bean后主動通過postprocess方法借助abstractautowirecapablebeanfactory完成對象相關屬性的注入以及對象的初始化流程。
v七、源碼分享
點我查看源碼,如果有任何疑問請關注公眾號后進行咨詢。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/hujunzheng/p/10463798.html