Spring中AOP的實現

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的專用標籤來完成相關的配置.這個標籤我也是正在研究,聽說挺好用的☺。

相關文章
相關標籤/搜索