spring(二)面向切面的AOP代理
面向切面程式設計,就是在不改變原始碼的基礎上,增加新的功能,對程式碼進行增強處理,代理模式。
關注兩件事:在什麼位置,執行什麼功能。由Spring AOP完成織入工作,日誌、異常處理、事務控制等。
增強處理主要有:
- 前置增強 before 在切入點前邊執行
- 後置增強 after-returning 在切入點後邊執行,如果有異常,就不執行
- 最終增強 after 在切入點後邊執行,無論怎樣都會執行,
- 環繞增強 round 最強大的增強,封裝了目標物件,對其進行控制。
- 異常丟擲增強 after-throwing 發生異常執行
首先新增需要的架包: aopalliance-1.0.jar;aspectjweaver-1.6.9.jar;spring-aop-3.2.13.RELEASE.jar
一、配置aop
1. 定義包含增強方法的javaBean
package aop; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class AopLogger { private static final Logger log = Logger.getLogger(AopLogger.class); public void before(JoinPoint jp){ log.info("=====>前置增強: 呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法,方法入參:"+jp.getArgs().toString()); } public void after(JoinPoint jp){ log.info("=====>最終增強:呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法"); } public void afterReturning(JoinPoint jp,Object result){ log.info("=====>後置增強帶返回值:呼叫 "+jp.getTarget()+"的"+jp.getSignature().getName()+" 方法,返回值:"+result); } public void afterException(JoinPoint jp,Exception e){ log.info("=====>異常丟擲增強 "+ jp.getSignature().getName() + "丟擲異常"+e); } public void around(ProceedingJoinPoint jp) throws Throwable{ //環繞增強得到了目標方法的控制權,可以獲取、修改目標方法的引數和返回值,封裝了目標物件,達到點對點的控制 log.info("=====>環繞增強執行 "); //相當於前置增強 try{ Object result = jp.proceed(); log.info("\n=====> 環繞增強結果 :"+result); //相當於後置增強 }catch(Throwable e){ log.info("=====>環繞增強丟擲異常:"+e); //相當於異常丟擲增強 throw e; }finally{ log.info("=====>環繞增強最後 "); //相當於最終增強 } } }
spring 會自動注入JoinPoint 例項。
2..建立目標物件
package aop;
public class PointDemo {
public String method1(String name){
System.out.println("======> 執行 method1, name is : "+name);
return name;
}
}
method1作為切入點
3. 配置applicationContext.xml
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <!--注入例項 --> <bean id="pointDemo" class="aop.PointDemo"></bean> <bean id="aopLogger" class="aop.AopLogger"></bean> <aop:config> <!--1. 定義一個切入點 --> <aop:pointcut expression="execution(public * method1(..))" id="pointCut"/> <!-- 2. 引用包含增強方法的Bean --> <aop:aspect ref="aopLogger"> <aop:before method="before" pointcut-ref="pointCut"/><!--前置增強 --> <aop:after method="after" pointcut-ref="pointCut"/><!-- 最終曾強 不論是否發生異常都執行--> <aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="result"/><!-- 帶返回值的後置增強 有異常就不執行了 --> <aop:after-throwing method="afterException" pointcut-ref="pointCut" throwing="e"/> <!-- 異常丟擲增強 --> <aop:around method="around" pointcut-ref="pointCut"/> </aop:aspect> </aop:config> </beans>
有關aop的配置都放在<aop: config> 標籤內;配置切入點的標籤<aop: pointcut>的expression屬性有多種表示式:
- public * method1(String name); 匹配所有返回值型別
- public void * (name); 匹配所有方法名
- public void method1(..); “..”匹配所有型別返回值;
- * com.*.*(..); 匹配com包下所有的類的方法;
- * com..*.*(..); 匹配com包及其子包所有類的方法
4. 測試
package aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext1.xml");
PointDemo pd = (PointDemo)ac.getBean("pointDemo");
pd.method1("張三");
}
}
講環繞增強註釋掉的結果:
INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@6e171cd7 ======> 執行 method1, name is : 張三 INFO - =====>最終增強:呼叫 [email protected]的method1 方法 INFO - =====>後置增強帶返回值:呼叫 [email protected]的method1 方法,返回值:張三
加上環繞增強的結果:
INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@52e6fdee INFO - =====>環繞增強執行 INFO - =====> 環繞增強結果 :張三 ======> 執行 method1, name is : 張三 INFO - =====>環繞增強最後 INFO - =====>後置增強帶返回值:呼叫 [email protected]的method1 方法,返回值:null INFO - =====>最終增強:呼叫 [email protected]的method1 方法
可以看到,後置增強返回值為null,所以環繞增強最好別和其他的一起用。
5. 改造 目標類,使其發生異常,測試異常丟擲增強;
package aop;
public class PointDemo {
public String method1(String name){
System.out.println("======> 執行 method1, name is : "+name);
String str="";
System.out.println(str.equals(""));
return name;
}
}
測試異常:
INFO - =====>前置增強: 呼叫 [email protected]的method1 方法,方法入參:[Ljava.lang.Object;@52e6fdee INFO - =====>環繞增強執行 ======> 執行 method1, name is : 張三INFO - =====>環繞增強丟擲異常:java.lang.NullPointerException INFO - =====>環繞增強最後
INFO - =====>異常丟擲增強 method1丟擲異常java.lang.NullPointerException INFO - =====>最終增強:呼叫 [email protected]的method1 方法 Exception in thread "main" java.lang.NullPointerException at aop.PointDemo.method1(PointDemo.java:7) at aop.PointDemo$$FastClassBySpringCGLIB$$93985287.invoke(<generated>)
丟擲了異常。