Spring中整合了AOP的功能,雖然有不足,沒有專門作AOP框架的那麼完美,可是用一用感受仍是不錯的正則表達式
一些概念:spring
AOP 面向切面編程編程
aspect 切面/切面類(我我的認爲一個真正被解耦的程序,切面類中的功能能夠切入到 任何一個目標類中 無所謂是service層或者說是dao層中的類)框架
joinPoint 鏈接點測試
在spring的aop中只有 類中的方法 能夠作鏈接點,每個方法均可以是一個鏈接點.spa
pointCut 切入點 代理
一組鏈接點的集合code
advice 通知/攔截器xml
用來控制切面類未來究竟是織入到切入點的前面、後面或者是拋異常的時候。對象
adivsor 加強器
用來篩選類中的哪些方法是咱們的鏈接點(哪些方法須要被攔截).
target 目標對象
proxy 代理對象
wave 織入
-----------------------
advice(通知)的類型:
前置通知(Before advice):
在某些鏈接點(join point)以前執行的通知
返回後通知(After returning advice):
在某些鏈接點(join point)正常完成後執行的通知(方法正常結束,沒有異常)
拋出異常後通知(After throwing advice):
在某些鏈接點(join point)拋出異常退出時執行的通知
後通知(After (finally) advice):
當某些鏈接點(join point)退出的時候執行的通知
環繞通知(Around Advice):
包圍一個鏈接點(join point)的通知,例如事務的處理,就須要這樣的通知,由於事務須要在方法前開啓,在方法後提交,以及方法拋出異常時候回滾
注:在spring中,鏈接點(join point)指的就是方法
Spring中提供了AOP的實現方式 在XMl中配置只須要三步就能夠實現
1.配置目標類
2.配置攔截器(配置切面類【可選】)
3.配置代理對象
配置xml文件:
1.首先是配置目標類
<!-- 配置dao層對象 --> <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/> <!-- 配置一個測試帳戶 --> <bean name="account" class="com.briup.aop.pojo.Account"> <property name="id" value="1"></property> <property name="name" value="tom"></property> <property name="balance" value="1000"></property> </bean> <!-- 配置目標對象 --> <bean name="target" class="com.briup.aop.service.AccountServiceImpl"> <property name="accountDao" ref="dao"></property> <property name="account" ref="account"></property> </bean>
2.配置攔截器
<!-- 配置切面類 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面類對象 --> <property name="logger" ref="logger"></property> </bean>
3.配置代理對象
<!-- 這裏使用的是spring的一個代理對象工廠類產生的 --> <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 注入目標對象 --> <property name="target" ref="target"></property> <!-- 注入目標對象所實現的接口 能夠有多個接口 --> <!-- 注入代理類須要實現的接口 代理類實現接口與目標類實現接口相同 --> <property name="proxyInterfaces"> <list> <value>com.briup.aop.service.IAccountService</value> </list> </property> <!-- 注入advice 能夠有多個 --> <property name="interceptorNames"> <list> <value>beforeAdvice</value> </list> </property> </bean>
這樣配置有三個問題:
1.這個目標類對應接口下的方法都被加入了功能
2.須要爲每個目標類進行配置
3.目標類必須實現接口
首先咱們解決第一個問題
咱們的Spring中提供了advisor(加強器),加強器包裝了一下advice(攔截器),能夠篩選向接口中的那個方法添加功能
1.首先是配置目標類
<!-- 配置dao層對象 --> <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/> <!-- 配置一個測試帳戶 --> <bean name="account" class="com.briup.aop.pojo.Account"> <property name="id" value="1"></property> <property name="name" value="tom"></property> <property name="balance" value="1000"></property> </bean> <!-- 配置目標對象 --> <bean name="target" class="com.briup.aop.service.AccountServiceImpl"> <property name="accountDao" ref="dao"></property> <property name="account" ref="account"></property> </bean>
2.配置攔截器
<!-- 配置切面類 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面類對象 --> <property name="logger" ref="logger"></property> </bean>
3.添加加強器
<!-- 配置advisor 加強器--> <!-- 做用:篩選要攔截(要代理)的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice--> <property name="advice" ref="beforeAdvice"></property> <!-- 注入須要被攔截的目標對象中的方法(鏈接點) --> <property name="patterns"> <list> <value>.*bankAction</value> <!--單個字符出現0到屢次--> </list> </property> </bean> <!--RegexpMethodPointcutAdvisor默認的正則表達式選擇方法--> <!--NameMatchMethodPointcutAdvisor按照方法名匹配-->
4.配置代理對象
<!-- 這裏使用的是spring的一個代理對象工廠類產生的 --> <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 注入目標對象 --> <property name="target" ref="target"></property> <!-- 注入目標對象所實現的接口 能夠有多個接口 --> <!-- 注入代理類須要實現的接口 代理類實現接口與目標類實現接口相同 --> <property name="proxyInterfaces"> <list> <value>com.briup.aop.service.IAccountService</value> </list> </property> <!-- 注入advice/advisor 能夠有多個 --> <property name="interceptorNames"> <list> <value>advisor</value> </list> </property> </bean>
咱們處理了第一個問題,被處理的方法能夠指定了
咱們開始解決第二個問題
自動的進行配置:自動代理:DefaultAdvisorAutoProxyCreator類的使用
xml配置文件:
1.配置攔截器
<!-- 配置切面類 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面類對象 --> <property name="logger" ref="logger"></property> </bean>
2.添加加強器
<!-- 配置advisor --> <!-- 做用:篩選要攔截的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice --> <property name="advice" ref="beforeAdvice"></property> <!-- 注入須要被攔截的目標對象中的方法 --> <property name="patterns"> <list> <value>.*bankAction</value> </list> </property> </bean>
配置目標對象,這裏的對象中只要有加強器中的方法,就能夠看成代理對象,Cgilb代理默認的將含有加強器中的方法的
全部對象都進行了處理,好比如下這個target對象,從容器中拿出後就是加入了功能的了,可是這些對象得要放在一個容器下面
在Spring中最須要注意的就是對象在不在容器中,對象不在容器中就沒辦法受到Spring框架的控制了
<bean name="target" class="com.briup.aop.service.AccountServiceImpl"> </bean>
3.實現自動代理
<!-- 配置代理對象 --> <!-- 這裏使用自動代理的方式 autoproxy --> <!-- 注意:這不是一個工廠類,因此不能用過proxy來拿代理對象 --> <bean name="proxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean>
這樣作就能夠自動的對須要功能的方法進行代理處理了,也不用實現接口了
使用自動代理的時候須要注意的方面:
1.當前的配置裏面"必定要有"一個advisor的配置
2.不須要向自動代理類中注入任何信息
3.無論目標對象是否實現了一個或多接口,自動代理的方式都可以爲它產生代理對象(CGLib的方式).
4.從spring容器中拿代理對象的時候,須要經過目標對象的名字來拿。
5.spring如何肯定配置文件中哪一個bean是做爲目標對象:
經過advisor中篩選的方法,若是這個bean中含有advisor中所配置的方法,則這個bean未來稱爲咱們的目標對象進行代理
可是又有問題來了:
咱們對全部含有同名方法的類對象進行了處理,若是想爲指定類對象中的方法進行處理呢?
Spring一樣進行了處理:
經過名字進行自動代理:BeanNameAutoProxyCreator類的使用
xml配置文件:
1.配置攔截器
<!-- 配置切面類 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面類對象 --> <property name="logger" ref="logger"></property> </bean>
2.添加加強器
<!-- 配置advisor --> <!-- 做用:篩選要攔截的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice --> <property name="advice" ref="beforeAdvice"></property> <!-- 注入須要被攔截的目標對象中的方法 --> <property name="patterns"> <list> <value>.*bankAction</value> </list> </property> </bean>
<!-- 配置目標對象 -->
<bean name="target" class="com.briup.aop.service.AccountServiceImpl"> </bean> <bean name="target2" class="com.briup.aop.service.AccountServiceImpl"> </bean> <bean name="target3" class="com.briup.aop.service.AccountServiceImpl"></bean>
3.實現自動代理
<!-- 配置代理對象 --> <!-- 這裏使用自動代理的方式 autoproxybyname --> <bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 注入須要被代理的對象名字 --> <property name="beanNames"> <list> <value>target</value> <value>target2</value> <value>dao</value> <value>service*</value> </list> </property> <!-- 注入advice或者advisor --> <property name="interceptorNames"> <list> <value>advisor</value> </list> </property> </bean>
使用byName自動代理的時候須要注意的方面:
1.當前的配置裏面"有沒有"advisor的配置"都不要緊"
有advisor能夠精確選擇增強功能的方法,沒有就是類中的全部方法了
2.須要向自動代理類中注入被代理目標對象的名字已經advice或者advisor
就是說advisor中指定的方法在 被代理目標對象 中存在
3.無論目標對象是否實現了一個或多接口,自動代理的方式都可以爲它產生代理對象.
4.從spring容器中拿代理對象的時候,須要經過目標對象的名字來拿。
這一點在DefaultAdvisorAutoProxyCreator的使用中就說過了
能夠說 目標對象加入了功能,變成了代理對象
Spring中封裝了AspectJ因此咱們也可使用到這種框架的功能了,Spring中提供了aop:config標籤,使用aop的專用標籤來完成相關的配置.這個標籤我也是正在研究,聽說挺好用的☺。