v一、前言
本文章所講并沒有基于aspectj,而是直接通過cglib以及proxyfactorybean去創(chuàng)建代理bean。通過下面的例子,可以看出cglib方式創(chuàng)建的代理bean和proxyfactorybean創(chuàng)建的代理bean的區(qū)別。
v二、基本測(cè)試代碼
測(cè)試實(shí)體類,在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 { } |
測(cè)試類
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()); //標(biāo)識(shí)spring-generated proxies enhancer.setinterfaces( new class []{springproxy. class }); //設(shè)置增強(qiáng) 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 結(jié)束執(zhí)行..." ); return result; } return method.invoke(target, args); }); return enhancer.create(); } return bean; } } |
主要是代理 bpptestbean的test1方法。其實(shí)這種方式創(chuàng)建的代理bean使用問題的,@autowired字段沒有注入進(jìn)來,所以會(huì)有出現(xiàn)npe。methodproxy.invokesuper(target, args)
,這一行代碼是有問題的,targe是代理類對(duì)象,而真實(shí)的對(duì)象是postprocessbeforeinitialization(object bean, string beanname)
中的bean對(duì)象,此時(shí)bean對(duì)象@autowired字段已經(jīng)注入了。所以可以將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 結(jié)束執(zhí)行..." ); return result; }); pfb.addadvisor(advisor); return pfb.getobject(); } return bean; } } |
使用proxyfactorybean創(chuàng)建代理bean的時(shí)候,一定要一個(gè)targe對(duì)象的。advisor在切入的時(shí)候,會(huì)逐個(gè)執(zhí)行advice。invocation.getthis()
就是在通過proxyfactorybean創(chuàng)建代理bean的時(shí)候傳入的target對(duì)象。由于target對(duì)象就是postprocessbeforeinitialization(object bean, string beanname)
中的bean對(duì)象,所以@autowired字段也已經(jīng)注入進(jìn)來了。
v五、@autowired注解何時(shí)被處理
想必大家都知道@autowired字段的處理也是通過一個(gè)bpp,不過這個(gè)bpp比我們平常使用的要高級(jí)一些,它就是instantiationawarebeanpostprocessor。這個(gè)bpp可以實(shí)現(xiàn)bean的創(chuàng)建、屬性的注入和解析(比如@autowired、@value、@resource等等),大家可以參考一下commonannotationbeanpostprocessor(處理jsr-250相關(guān)注解),autowiredannotationbeanpostprocessor(處理@autowired、@value、@inject相關(guān)注解)。
instantiationawarebeanpostprocessor中有一個(gè)如下的方法,autowiredannotationbeanpostprocessor就是覆蓋這個(gè)方法實(shí)現(xiàn)了帶有相關(guān)注解屬性的自動(dòng)注入。
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方法實(shí)在spring abstractautowirecapablebeanfactory的populatebean方法中被調(diào)用。在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); } |
也就是先進(jìn)行了bean的屬性填充,然后進(jìn)行bean的初始化工作。initializebean方法中主要做了四件事。
1、invokeawaremethods
2、applybeanpostprocessorsbeforeinitialization
3、invokeinitmethods
4、applybeanpostprocessorsafterinitialization
其中2和4就是分別調(diào)用的普通的bpp中的postprocessbeforeinitialization方法和postprocessafterinitialization方法。
這就是為什么在bpp中創(chuàng)建代理bean的時(shí)候,對(duì)應(yīng)的目標(biāo)bean相關(guān)的@autowired字段已經(jīng)注入的原因了。
v六、instantiationawarebeanpostprocessor方式創(chuàng)建動(dòng)態(tài)代理bean
instantiationawarebeanpostprocessor接口中有個(gè)postprocessbeforeinstantiation方法,可以讓我們自己去實(shí)例化bean。通過查看abstractautowirecapablebeanfactory,方法調(diào)用:createbean方法 -> resolvebeforeinstantiation方法 -> applybeanpostprocessorsbeforeinstantiation方法 ->instantiationawarebeanpostprocessor#postprocessbeforeinstantiation方法,如果最終返回一個(gè)非null的實(shí)例,那么就不會(huì)再執(zhí)行docreatebean方法。這就意味著不會(huì)有bean屬性的填充和初始化的流程了,但是可以借助abstractautowirecapablebeanfactory幫助我們實(shí)現(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標(biāo)準(zhǔn)依賴注入方法autowirebean()處理 object對(duì)象的依賴注入 this .autowirebeanfactory.autowirebean(object); // 使用容器autowirebeanfactory標(biāo)準(zhǔn)初始化方法initializebean()初始化對(duì)象 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; } |
上圖代碼,可以幫組我們實(shí)現(xiàn)非spring容器bean自動(dòng)注入和初始化的功能。使用過spring security同學(xué)都知道,內(nèi)部也是用了這個(gè)方式解決對(duì)象中的屬性注入問題。如果你閱讀了spring security的源碼,你會(huì)發(fā)現(xiàn)很多對(duì)象,比如websecurity、providermanager、各個(gè)安全filter等,這些對(duì)象的創(chuàng)建并不是通過bean定義的形式被容器發(fā)現(xiàn)和注冊(cè)進(jìn)入spring容器的,而是直接new出來的。spring security提供的autowirebeanfactoryobjectpostprocessor這個(gè)工具類可以使這些對(duì)象具有容器bean同樣的生命周期,也能注入相應(yīng)的依賴,從而進(jìn)入準(zhǔn)備好被使用的狀態(tài)。
使用cglib在instantiationawarebeanpostprocessor 中創(chuàng)建動(dò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); //標(biāo)識(shí)spring-generated proxies enhancer.setinterfaces( new class []{springproxy. class }); //設(shè)置增強(qiáng) 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 結(jié)束執(zhí)行..." ); return result; } return methodproxy.invokesuper(target, args); }); return this .postprocess(enhancer.create()); } return null ; } ... } |
使用proxyfactorybean在instantiationawarebeanpostprocessor 中創(chuàng)建動(dò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 結(jié)束執(zhí)行..." ); return result; }); pfb.addadvisor(advisor); return pfb.getobject(); } return null ; } ... } |
上述向兩種方式,注意,實(shí)例化bean后主動(dòng)通過postprocess方法借助abstractautowirecapablebeanfactory完成對(duì)象相關(guān)屬性的注入以及對(duì)象的初始化流程。
v七、源碼分享
點(diǎn)我查看源碼,如果有任何疑問請(qǐng)關(guān)注公眾號(hào)后進(jìn)行咨詢。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。
原文鏈接:https://www.cnblogs.com/hujunzheng/p/10463798.html