這里的自動代理,我講的是自動代理bean對象,其實就是在xml中讓我們不用配置代理工廠,也就是不用配置class為org.springframework.aop.framework.ProxyFactoryBean的bean。
總結了一下自己目前所學的知識。
發現有三種方式實現自動代理
用Spring一個自動代理類DefaultAdvisorAutoProxyCreator:
1
|
< bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" data-filtered = "filtered" ></ 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
|
<!--?xml version="1.0" encoding="UTF-8"?--> < beans xmlns = "https://www.springframework.org/schema/beans" xmlns:context = "https://www.springframework.org/schema/context" xmlns:tx = "https://www.springframework.org/schema/tx" xmlns:xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!-- 代理前原對象 --> < bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean > <!-- 切面 = 切點+通知 --> < bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" > <!-- 切點 --> < property name = "patterns" > < list > < value >.*run.*</ value > </ list > </ property > <!-- 通知-由我們寫,實際代理動作 --> < property name = "advice" > < bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean > </ property > </ bean > <!-- 代理工廠 --> < bean class = "org.springframework.aop.framework.ProxyFactoryBean" id = "personProxied" > <!-- 放入原型對象 --> < property name = "target" ref = "person" ></ property > <!-- 放入切面 --> < property name = "interceptorNames" > < list > < value >advisor</ value > </ list > </ property > </ bean > </ beans > |
現在改用自動代理,如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
< beans ... = "" > <!-- 代理前原對象 --> < bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean > <!-- 切面 = 切點+通知 --> < bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" > <!-- 切點 --> < property name = "patterns" > < list > < value >.*run.*</ value > </ list > </ property > <!-- 通知-由我們寫,實際代理動作 --> < property name = "advice" > < bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean > </ property > </ bean > <!-- 自動代理 --> < bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" ></ bean > </ beans > |
測試方法
1
2
3
4
5
6
7
8
|
@Test //自動代理 public void demo4(){ ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/4.xml" ); //我們直接在這里獲取Person對象就可以了,因為在最開始xml文件newPerson對象后,Spring就已經幫我們代理了! Person p =ctx.getBean(Person. class ); p.run(); p.say(); } |
相對于前面,也就是把代理工廠部分換成自動代理了。
演示結果:
自己寫一個自動代理底層實現:
我們也可以寫一個類,來實現DefaultAdvisorAutoProxyCreator自動代理的功能!
首先,我們需要實現一個接口,也就是BeanPostProcessor接口。
BeanPostProcessor接口作用是:如果我們需要在Spring容器完成Bean的實例化、配置和其他的初始化前后添加一些自己的邏輯處理,我們就可以定義一個或者多個BeanPostProcessor接口的實現,然后注冊到容器中。
而我們想要在原型對象bean被創建之后就代理了,就必須在原來的容器中拿到原來的原型對象,需要拿到原來spring容器中的切面對象,這個時候,我們就需要原來的容器,這個時候就需要另一個接口,也就是ApplicationContextAware接口!
通過這2個接口,我們就可以實現自動代理了。
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
35
|
package cn.hncu.xmlImpl; import org.springframework.aop.Advisor; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class MyAutoProxy implements BeanPostProcessor,ApplicationContextAware{ private ApplicationContext applicationContext= null ; //bean創建之前調用 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; //在這里,我們直接放行 } //bean創建之后調用 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { ProxyFactoryBean factory = new ProxyFactoryBean(); //把原型對象放入代理工廠 factory.setTarget(bean); //在這里 Advisor adv = applicationContext.getBean(Advisor. class ); factory.addAdvisor(adv); //返回被代理后的對象 return factory.getObject(); } //拿到原來的spring中的容器 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this .applicationContext=applicationContext; } } |
5.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
< beans... > <!-- 代理前原對象 --> < bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean > <!-- 切面 = 切點+通知 --> < bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" > <!-- 切點 --> < property name = "patterns" > < list > < value >.*run.*</ value > </ list > </ property > <!-- 通知-由我們寫,實際代理動作 --> < property name = "advice" > < bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean > </ property > </ bean > <!-- 自己寫的自動代理 --> < bean class = "cn.hncu.xmlImpl.MyAutoProxy" ></ bean > </ beans... > |
測試方法:
1
2
3
4
5
6
7
|
@Test //自己實現的自動代理 public void demo5(){ ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/5.xml" ); Person p =ctx.getBean(Person. class ); p.run(); p.say(); } |
測試結果就不上圖了,和前面是一樣的。
其實很多時候,我們如果自己去練一下底層,對上層的框架更好理解。
還有一種方法。
使用aop標簽配自動代理
需要在beans加一個命名空間
xmlns:aop=https://www.springframework.org/schema/aop
還需要配xsi:schemaLocation,為aop加一個網絡地址。
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd
我們需要一個aspectjweaver-jar包:
xml配置文件:
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
|
<!--?xml version="1.0" encoding="UTF-8"?--> < beans xmlns = "https://www.springframework.org/schema/beans" xmlns:aop = "https://www.springframework.org/schema/aop" xmlns:context = "https://www.springframework.org/schema/context" xmlns:tx = "https://www.springframework.org/schema/tx" xmlns:xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd "> <!-- 利用sop標簽實現自動代理 --> </ aop:aspectj-autoproxy > <!-- 代理前原對象 --> < bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean > <!-- 切面 = 切點+通知 --> < bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" > <!-- 切點 --> < property name = "patterns" > < list > < value >.*run.*</ value > </ list > </ property > <!-- 通知-由我們寫,實際代理動作 --> < property name = "advice" > < bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean > </ property > </ bean > </ beans > |
測試方法:
1
2
3
4
5
6
7
|
@Test //自動代理 public void demo6(){ ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/6.xml" ); Person p =ctx.getBean(Person. class ); p.run(); p.say(); } |
測試結果:
個人覺得能學會使用一種就OK了,不用全部記下來,為了學習,都了解一下就好,別人寫出來,能看懂就好。
哈哈,其實底層學好了,自己寫的時候,就算不會用Spring的自動代理,自己寫出來底層也是蠻好的嘛
總結
以上本文關于Spring AOP攔截-三種方式實現自動代理詳解的全部內容,希望對大家有所幫助。有什么問題可以隨時留言,小編會及時回復大家的。感謝朋友們對本站的支持!
原文鏈接:https://www.2cto.com/kf/201609/545023.html