1.什么是SpringAOP
什么是aop:Aspect Oriented Programming的縮寫,面向切面編程,通過預編譯和動態代理實現程序功能的
統一維護的一種技術
主要功能:日志記錄,性能統計,安全控制,事務處理,異常處理等
2.SpringAOP框架的用途
允許用戶控制自己的方面,以完成OOP和AOP的互補使用
OOP:模擬真實的世界,一切皆是對象
3.AOP的實現方式
3.1預編譯
-AspectJ 完整的面向切面編程解決方案--》spring不是完整的解決方案,不過spring提供比較好的實現方式,當然spring是同時也是支持這種方式的,這也是一種常用的方式
3.2運行期間動態代理(JDK動態代理,CGLib動態代理)
-SpringAop,JbossAop
Spring的AOP使用純java實現,無需特殊的編譯過程,不需要控制類的加載器層次,目前只支持方法的執行的連接點(通知Spring Bean某個方法執行)
不是為了提供完整AOP實現;而是側重於一種AOP於IOC容器之間的整合,SpringAOP不會AspectJ(完整的AOP解決方案)競爭
Spring沒有使用AspectJ的時候,也可以通過如下方式實現AOP
Spring AOP 默認使用標准的JavaSE動態代理作為AOP代理,這使得任何接口(或者集合)都可以被代理
Spring AOP 中也可以使用CGLIB代理(如果一個業務對象沒有實現一個接口)
有接口的:使用JDK的動態里
無接口的:使用CGLIB代理
4.SpringAOP中的一些概念
SpringAOP主要圍繞以下概念展開:
連接點(Joinpoint)程序執行過程中某個特定的連接點
通知(Advice) 在切面的某個特的連接點上執行的動作
切入點(Pointcut)匹配連接的斷言,在Aop中通知和一個切入點表達式關聯
引入(Intruduction) 在不修改類代碼的前提下,為類添加新的方法和屬性
目標對象(Target Object) 被一個或者多個切面所通知的對象
Aop代理(AOP Proxy) AOP框架創建的對象,用來實現切面契約(aspect contract)(包括方法執行等)
織入(Weaving)把切面連接到其他的應用程序類型或者對象上,並創建一個被通知的對象,氛圍:編譯時織入,類加載時織入,執行時織入
通知類型Advice:
返回后通知(after returning advice)在某個連接點(jion point)正常執行完后執行通知
拋出異常通知(after throwing advice) 在方法異常退出時執行的通知
后通知(after(finally) advice)在方法拋出異常退出時候的執行通知(不管正常返回還是異常退出)
環繞通知(around advice) 包圍一個連接點(jion point)的通知
切入點Pointcut:SpringAOP占時僅僅支持方法的連接點
execution()是最常用的切點函數,其語法如下所示:
整個表達式可以分為五個部分:
1、execution(): 表達式主體。
2、第一個*號:表示返回類型,*號表示所有的類型。
3、包名:表示需要攔截的包名,后面的兩個句點表示當前包和當前包的所有子包,com.sample.service.impl包、子孫包下所有類的方法。
4、第二個*號:表示類名,*號表示所有的類。
5、*(..):最后這個星號表示方法名,*號表示所有的方法,后面括弧里面表示方法的參數,兩個句點表示任何參數。
execution(public * *(..)) 切入點為執行所有的public方式時
execution(* set*(..)) 切入點執行所有的set開始的方法時
execution(* com.xyz.service.Account.*(..)) 切入點執行Account類的所有方法時
execution(* com.xyz.service.*.*(..))切入點執行com.xyz.service包下的所有方法時
execution(* com.xyz.service..*.*(..)) 切入點執行com.xyz.service包以及其子包的所有的方法時
上邊這種方式aspectj和springaop通用的,其他方式可以自己查找資料
推薦:
http://blog.csdn.net/abcd898989/article/details/50809321
http://blog.csdn.net/peng658890/article/details/7223046
5.SpringAOP實現
我們在Java項目開發中,AOP常見的配置有如下3種:
a.基於SpringAOP容器的實現,使用AspectJ(Spring封裝了AspectJ的使用),這是一種比較常用的方式,可以很容易看清代碼結構
b.運行期間的動態代理實現,這是一種比較老的實現方式,比較繁瑣
c.注解實現,這種方式開發起來簡單,但是不利於后期維護,比如說很難找出你所有使用了SpringAOP注解的地方
這里我主要介紹第一種,和第二種的使用
5.1SpringAOP中的容器實現
5.1.1 前置通知 before
和aspect元素(注意這些元素的出現是由順序的)
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
- <!-- 切面類 -->
- <bean id="myAspect" class="com.xxx.spring.aop.bean.annotation.aop.MyAspect"></bean>
- <!-- 業務類 -->
- <bean id="aspectBiz" class="com.xxx.spring.aop.bean.annotation.aop.AspectBiz"></bean>
- <!-- aop配置 可以配置多個-->
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名包含Biz的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法-->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- </aop:aspect>
- </aop:config>
- </beans>
切面類:
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- }
- //業務類
- public class AspectBiz {
- public void biz(){
- System.out.println("Aspect biz");
- }
- }
- @Test
- public void aspectBefore(){
- ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/spring-aop-schema-advice.xml");
- AspectBiz aspectBiz = (AspectBiz) ac.getBean("aspectBiz");
- aspectBiz.biz();
- }
- aspect before
- Aspect biz
5.1.2后置通知after-returning
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名以Biz結尾的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- <!-- 返回之后的通知 -->
- <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
- </aop:aspect>
- </aop:config>
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- public void afterReturning(){
- System.out.println("aspect afterReturning");
- }
- }
- aspect before
- Aspect biz
- aspect afterReturning
5.1.3異常通知after-throwing
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名以Biz結尾的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- <!-- 返回之后的通知 -->
- <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
- <!-- -->
- <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>
- </aop:aspect>
- </aop:config>
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- public void afterReturning(){
- System.out.println("aspect afterReturning");
- }
- public void afteThrowing(){
- System.out.println("aspect afteThrowing");
- }
- }
業務類:
- public void biz(){
- System.out.println("Aspect biz");
- throw new RuntimeException(); //出現異常的時候afteThrowing才會執行
- }
測試和結果:
- aspect before
- Aspect biz
- aspect afteThrowing
- 上邊的結果由於拋出異常后,不會正常的返回所有沒有aspect afterReturning輸出
5.1.4最終通知after(finally) advice
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名以Biz結尾的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- <!-- 返回之后的通知 -->
- <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
- <!-- -->
- <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>
- <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->
- <aop:after method="after" pointcut-ref="myPointcut"/>
- </aop:aspect>
- </aop:config>
切面類:
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- public void afterReturning(){
- System.out.println("aspect afterReturning");
- }
- public void afteThrowing(){
- System.out.println("aspect afteThrowing");
- }
- public void after(){
- System.out.println("aspect after(finally)");
- }
- }
業務類:
- //業務類
- public class AspectBiz {
- public void biz(){
- System.out.println("Aspect biz");
- throw new RuntimeException();
- }
- }
- aspect before
- Aspect biz
- aspect afteThrowing
- aspect after(finally)
- 如果業務類如下:沒有異常,
- public class AspectBiz {
- public void biz(){
- System.out.println("Aspect biz");
- }
- }
- aspect before
- Aspect biz
- aspect after(finally)
5.1.5環繞通知around
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名以Biz結尾的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- <!-- 返回之后的通知 -->
- <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
- <!-- -->
- <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>
- <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->
- <aop:after method="after" pointcut-ref="myPointcut"/>
- <!-- adroun advice 環繞通知,方法的第一參數必須是ProceedingJoinPoint類型 -->
- <aop:around method="around" pointcut-ref="myPointcut"/>
- </aop:aspect>
- </aop:config>
切面類:
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- public void afterReturning(){
- System.out.println("aspect afterReturning");
- }
- public void afteThrowing(){
- System.out.println("aspect afteThrowing");
- }
- public void after(){
- System.out.println("aspect after(finally)");
- }
- public void around(ProceedingJoinPoint joinPoint){
- Object object = null;
- try{
- System.out.println("aspect around 1"); //方法執行前
- object = joinPoint.proceed(); //代表業務方法的執行
- System.out.println("aspect around 1"); //方法執行后
- }catch(Throwable e){
- e.printStackTrace();
- }
- }
- }
測試結果:
- aspect around 1
- Aspect biz
- aspect around 1
從結果可以看出,joinPoint.proceed其實就是執行業務方法,我們可以在其之前做和之后做一些操作
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
- <!-- 切面類 -->
- <bean id="myAspect" class="com.xxx.spring.aop.bean.annotation.aop.MyAspect"></bean>
- <!-- 業務類 -->
- <bean id="aspectBiz" class="com.xxx.spring.aop.bean.annotation.aop.AspectBiz"></bean>
- <!-- aop配置 可以配置多個-->
- <aop:config>
- <!-- 切面類 -->
- <aop:aspect id="aspectTest" ref="myAspect">
- <!-- 切入點 標識切入點 aop包下類名以Biz結尾的類的所有方法-->
- <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>
- <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->
- <aop:before method="before" pointcut-ref="myPointcut"/>
- <!-- 返回之后的通知 -->
- <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
- <!-- -->
- <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>
- <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->
- <aop:after method="after" pointcut-ref="myPointcut"/>
- <!-- adroun advice 環繞通知,方法的第一參數必須是ProceedingJjoinPoint類型 -->
- <!-- <aop:around method="around" pointcut-ref="myPointcut"/> -->
- <!-- 參數傳遞 -->
- <aop:around method="aroundInit" pointcut="execution(* com.xxx.spring.aop.bean.annotation.aop.AspectBiz.init(String,int))
- and args(bizName,times)"/>
- </aop:aspect>
- </aop:config>
- </beans>
其中,通知中也可以單獨指定的pointcut,切入點中,我們單獨指定了init方法,且指定了方法的參數類型,和方法參數的名字,其中方法參數名字,可以更實際的方法參數名字不同,比如說init(String biz,int t) 都是可以匹配到的,不過為了維護方便,最好還是都一樣。
- /*
- * 聲明一個切面類
- * */
- public class MyAspect {
- public void before(){
- System.out.println("aspect before");
- }
- public void afterReturning(){
- System.out.println("aspect afterReturning");
- }
- public void afteThrowing(){
- System.out.println("aspect afteThrowing");
- }
- public void after(){
- System.out.println("aspect after(finally)");
- }
- public void around(ProceedingJoinPoint joinPoint){
- Object object = null;
- try{
- System.out.println("aspect around 1"); //方法執行前
- object = joinPoint.proceed(); //代表業務方法的執行
- System.out.println("aspect around 2"); //方法執行后
- }catch(Throwable e){
- e.printStackTrace();
- }
- }
- //AOP中參數的傳遞
- public void aroundInit(ProceedingJoinPoint joinPoint,String bizName,int times){
- System.out.println(bizName+"--"+times);
- Object object = null;
- try{
- System.out.println("aspect around 1"); //方法執行前
- object = joinPoint.proceed(); //代表業務方法的執行
- System.out.println("aspect around 1"); //方法執行后
- }catch(Throwable e){
- e.printStackTrace();
- }
- }
- }
業務類:
- public class AspectBiz {
- public void biz(){
- System.out.println("Aspect biz");
- }
- public void init(String bizName,int times){
- System.out.println("aspectBiz init:"+bizName+" "+times);
- }
- }
測試:
- @Test
- public void aspectAround(){
- ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/spring-aop-schema-advice.xml");
- AspectBiz aspectBiz = (AspectBiz) ac.getBean("aspectBiz");
- aspectBiz.init("init", 3);
- }
- aspect before
- init--3
- aspect around 1
- aspectBiz init:init 3
- aspect around 1
- aspect after(finally)
- aspect afterReturning
- AfterClass 標注的方法 會最后執行
6.Advisor
Advisor就像一個小的自包含,只有一個advice切面通過一個bean標識,並且必須實現一個advice接口,同時advisor也可以很好的利用aspectJ的切入點表達式Spring通過配置文件中 <aop:advisor>元素支持advisor實際使用中,大多數情況下它會和transactional advice配合使用,用於事務控制- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
- <bean name="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="configLocation">
- <!-- 路徑位於src下 -->
- <value>classpath:hibernate.cfg.xml</value>
- </property>
- </bean>
- <!-- 事物配置 -->
- <bean id="txManager"
- class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory">
- <ref local="sessionFactory" />
- </property>
- </bean>
- <!-- advisor配置 配置事務處理的Bean,定義切面(advice)
- 由於getxxx,queryxxx,findxxx不涉及事務,可以設置read-only為true
- -->
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="get*" read-only="true" />
- <tx:method name="query*" read-only="true" />
- <tx:method name="find*" read-only="true" />
- <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
- <tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
- <tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
- <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
- <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
- </tx:attributes>
- </tx:advice>
- <!-- aop配置 -->
- <aop:config>
- <!-- 給impl包下的所有的方法配置adivce -->
- <aop:pointcut expression="excution(* com.xxx.spring.aop.bean.annotation.service.impl..(..))" id="serviceMethod" />
- <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
- </aop:config>
- </beans>
關於spring的事務控制將會在另外一篇文章中介紹。
7.SpringAOP代理實現
7.1.1ProxyFactoryBean
7.1.2使用代理實現環繞通知around
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean><!-- advice在方法執行前后添加我們的操作 -->
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!--proxyInterfaces 如果ProxyFactoryBean的proxyInterfaces屬性沒有被設置,但是目標類實現類一個或多個接口,
- 那么ProxyFactoryBean將自動檢測到這個目標類已經實現了至少一個接口,創建一個基於JDK的代理 -->
- <property name="proxyInterfaces" value="com.xxx.spring.aop.bean.UserDao"></property>
- <!-- 注入目標對象(注入被代理的對象) -->
- <property name="target" ref="target"></property>
- <!-- 注入代理對象所要執行的處理程序,通知配置 -->
- <property name="interceptorNames">
- <list>
- <value>advice</value>
- </list>
- </property>
- </bean>
- </beans>
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
如果有多個通知可以寫成:
- <property name="interceptorNames">
- <list>
- <value>advice</value>
- </list>
- </property>
- import java.util.Date;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- public class AdviceTest implements MethodInterceptor{
- @Override
- public Object invoke(MethodInvocation method) throws Throwable {
- System.out.println("方法開始執行"+new Date());
- method.proceed();
- System.out.println("方法執行完畢"+new Date());
- return null;
- }
- }
- //委托類
- public class UserDaoImpl implements UserDao {
- @Override
- public void saveUser() {
- System.out.println("保存用戶");
- }
- @Override
- public void deleteUser() {
- System.out.println("刪除用戶");
- }
- @Override
- public void updateUser() {
- System.out.println("更新用戶");
- }
- }
- public interface UserDao {
- public abstract void saveUser();
- public abstract void deleteUser();
- public abstract void updateUser();
- }
- @Test
- public void advice(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/advice.xml");
- UserDao userDao = factory.getBean("proxy", UserDao.class);
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
- 方法開始執行Sun Sep 11 21:02:12 CST 2016
- 保存用戶
- 方法執行完畢Sun Sep 11 21:02:12 CST 2016
- 方法開始執行Sun Sep 11 21:02:12 CST 2016
- 刪除用戶
- 方法執行完畢Sun Sep 11 21:02:12 CST 2016
- 方法開始執行Sun Sep 11 21:02:12 CST 2016
- 更新用戶
- 方法執行完畢Sun Sep 11 21:02:12 CST 2016
7.1.3使用動態代理實現前置通知before
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 注入目標對象(注入被代理的對象) -->
- <property name="target" ref="target"></property>
- <!-- 注入代理對象需要實現的所有接口 -->
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
- <!-- 注入代理對象所要執行的處理程序 -->
- <property name="interceptorNames">
- <array>
- <value>before</value>
- </array>
- </property>
- </bean>
- </beans>
切面前置通知實現類:
- import java.lang.reflect.Method;
- import org.springframework.aop.MethodBeforeAdvice;
- public class BeforeTest implements MethodBeforeAdvice{
- @Override
- public void before(Method method, Object[] obj, Object object)
- throws Throwable {
- System.out.println("version 1.0 author tom "+method.getName()+" is execute");
- }
- }
測試:
- @Test
- public void before(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/before.xml");
- UserDao userDao = factory.getBean("proxy", UserDao.class);
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
- version 1.0 author tom saveUser is execute
- 保存用戶
- version 1.0 author tom deleteUser is execute
- 刪除用戶
- version 1.0 author tom updateUser is execute
- 更新用戶
7.1.4后置通知afterReturning
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="after" class="com.xxx.spring.aop.bean.AfterTest"></bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 注入目標對象(注入被代理的對象) -->
- <property name="target" ref="target"></property>
- <!-- 注入代理對象需要實現的所有接口 -->
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
- <!-- 注入代理對象所要執行的處理程序 -->
- <property name="interceptorNames">
- <array>
- <value>after</value>
- </array>
- </property>
- </bean>
- </beans>
切面后置通知:
- import java.lang.reflect.Method;
- import org.springframework.aop.AfterReturningAdvice;
- public class AfterTest implements AfterReturningAdvice {
- @Override
- public void afterReturning(Object arg0, Method arg1, Object[] arg2,
- Object arg3) throws Throwable {
- System.out.println(arg1.getName()+" is over!");
- }
- }
- @Test
- public void after(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/after.xml");
- UserDao userDao = factory.getBean("proxy", UserDao.class);
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 注入目標對象(注入被代理的對象) -->
- <property name="target" ref="target"></property>
- <!-- 注入代理對象需要實現的所有接口 -->
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
- <!-- 注入代理對象所要執行的處理程序 -->
- <property name="interceptorNames">
- <list>
- <value>throws</value>
- </list>
- </property>
- </bean>
- </beans>
異常通知切面:
- package com.briup.spring.aop.bean;
- import java.lang.reflect.Method;
- import org.springframework.aop.ThrowsAdvice;
- public class ThrowsAdiviceTest implements ThrowsAdvice{
- public void afterThrowing(Method method,Object[] args,Object target,Exception ex)throws Throwable{//Throwable subclass
- System.out.println("afterThrowing 2 ...."+method.getName()+" "+ target.getClass().getName());
- }
- }
- @Test
- public void throwTest(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/throw.xml");
- UserDao userDao = factory.getBean("proxy", UserDao.class);
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.briup.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean>
- <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>
- <!-- 切入點 -->
- <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
- <property name="mappedNames">
- <list>
- <value>sa*</value>
- </list>
- </property>
- </bean>
- <!-- advisor -->
- <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice" ref="throws"></property>
- <property name="pointcut" ref="pointcutBean"></property>
- </bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 注入目標對象(注入被代理的對象) -->
- <property name="target" ref="target"></property>
- <!-- 注入代理對象需要實現的所有接口 -->
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
- <!-- 注入代理對象所要執行的處理程序 -->
- <property name="interceptorNames">
- <list>
- <value>defaultAdvisor</value>
- <value>throws</value>
- </list>
- </property>
- </bean>
- </beans>
如上邊切入點配置:
- <!-- 切入點 -->
- <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
- <property name="mappedNames">
- <list>
- <value>sa*</value>
- </list>
- </property>
- </bean>
切面:
- <!-- advisor -->
- <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice" ref="advice"></property>
- <property name="pointcut" ref="pointcutBean"></property>
- </bean>
7.1.7使用匿名的代理對象
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean>
- <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>
- <!-- 切入點 -->
- <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
- <property name="mappedNames">
- <list>
- <value>sa*</value>
- </list>
- </property>
- </bean>
- <!-- advisor -->
- <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice" ref="advice"></property>
- <property name="pointcut" ref="pointcutBean"></property>
- </bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 注入目標對象(注入被代理的對象),使用匿名的方式 -->
- <property name="target">
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- </property>
- <!-- 注入代理對象需要實現的所有接口 -->
- <property name="interfaces">
- <array>
- <value>com.xxx.spring.aop.bean.UserDao</value>
- </array>
- </property>
- <!-- 注入代理對象所要執行的處理程序 -->
- <property name="interceptorNames">
- <list>
- <value>defaultAdvisor</value>
- <value>throws</value>
- </list>
- </property>
- </bean>
- </beans>
7.1.8IntroductionInterceptor
8.自動代理實現
8.1.BeanNameAutoProxyCreator
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>
- <!-- 配置代理對象 -->
- <bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <!-- 注入需要被代理的對象名字,會代理所有以targ開始的bean -->
- <property name="beanNames">
- <list>
- <value>targ*</value>
- </list>
- </property>
- <!-- 注入advice或者advisor -->
- <property name="interceptorNames">
- <list>
- <value>before</value>
- </list>
- </property>
- </bean>
- </beans>
- //委托類
- public class UserDaoImpl implements UserDao {
- @Override
- public void saveUser(){
- System.out.println("保存用戶");
- }
- @Override
- public void deleteUser() {
- System.out.println("刪除用戶");
- }
- @Override
- public void updateUser() {
- System.out.println("更新用戶");
- }
- }
- @Test
- public void autoAdvisor(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/autoAdvisor.xml");
- UserDao userDao = factory.getBean("target", UserDao.class);//autoAdvisor只能通過委托類的名字來拿
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
結果:
- version 1.0 author tom saveUser is execute
- 保存用戶
- version 1.0 author tom deleteUser is execute
- 刪除用戶
- version 1.0 author tom updateUser is execute
- 更新用戶
8.2DefaultAdvisorAutoProxyCreator
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
- <!-- 配置委托類 -->
- <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
- <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->
- <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>
- <!-- 配置advisor -->
- <!-- 作用:篩選要攔截的方法 -->
- <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <!-- 注入advice -->
- <property name="advice" ref="before"></property>
- <!-- 注入需要被攔截的目標對象中的方法 -->
- <property name="patterns">
- <list>
- <value>.*deleteUser</value>
- </list>
- </property>
- </bean>
- <!-- 配置代理對象,當前IoC容器中自動應用,不用顯示應用advisor的bean定義 -->
- <bean name="proxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
- </beans>
- @Test
- public void autoProxyByName(){
- BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/autoProxyByName.xml");
- UserDao userDao = factory.getBean("target", UserDao.class);
- userDao.saveUser();
- userDao.deleteUser();
- userDao.updateUser();
- }
結果:
- 保存用戶
- version 1.0 author tom deleteUser is execute
- 刪除用戶
- 更新用戶
http://blog.csdn.net/abcd898989/article/details/50809321
http://blog.csdn.net/peng658890/article/details/7223046