AOP是在處理Cross-cutting concerns,將某段代碼(日誌)動態切入(不把日誌程式hardcode到業務邏輯方法中)到指定方法(加減乘除)的指定位置進行運行。
昨天我們學到了AOP中如何透過JDK動態代理與CGLIB代理來達到將程式碼動態切入,並透過pointcut expression決定要切入哪些方法
今日我們將探討AOP的Advice如何運作
Advice的執行flow可以參考下面的順序,執行順性分為兩種,正常執行與異常執行只差在最後一個執行步驟(@AfterReturning/AfterThrowing)
try{
@Before
method.invoke(obj,args);
@AfterReturning
}catch(){
@AfterThrowing
}finally{
@After
}
@Before -> @After -> @AfterReturning
@Before -> @Afte -> @AfterThrowing
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.swj"></context:component-scan>
<!-- 啟動AOP -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
@Service
public class MyCalculator {
public int add(int i, int j) {
int result = i+j;
return result;
}
public int sub(int i, int j) {
int result = i-j;
return result;
}
public int mul(int i, int j) {
int result = i*j;
return result;
}
public int div(int i, int j) {
int result = i/j;
return result;
}
}
@Aspect
@Component
public class LogUtils {
@Before("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logStart(){
System.out.println("method start");
}
@AfterReturning("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logReturn(){
System.out.println("method completed,result is");
}
@After("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logEnd(){
System.out.println("method end");
}
@AfterThrowing("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logException(){
System.out.println("method throws exception");
}
}
@Test
public void testDay20(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean20.xml");
System.out.println("容器啟動完成....");
MyCalculator calculator = ioc.getBean(MyCalculator.class);
calculator.add(1,1);
System.out.println("===================");
calculator.div(1,0);
}
Result
參數加入JointPoint,JointPoint封裝目標訪法的資訊
@Aspect
@Component
public class LogUtils {
@Before("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logStart(JoinPoint jointPoint){
//取得方法名稱,與parameter
System.out.println("["+jointPoint.getSignature().getName()+"] method start,parameter:"+Arrays.asList(jointPoint.getArgs()));
}
@AfterReturning("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logReturn(JoinPoint joinPoint){
System.out.println("["+joinPoint.getSignature().getName()+"] method completed,result is");
}
@After("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logEnd(JoinPoint joinPoint){
System.out.println("["+joinPoint.getSignature().getName()+"] method end");
}
@AfterThrowing("execution(public int com.swj.MyCalculator.*(int,int))")
public static void logException(JoinPoint joinPoint){
System.out.println("["+joinPoint.getSignature().getName()+"] method throws exception");
}
}
@Test
public void testDay20(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean20.xml");
System.out.println("容器啟動完成....");
MyCalculator calculator = ioc.getBean(MyCalculator.class);
calculator.add(1,1);
}
Result
Advice是由spring透過反射調用,所以需要告訴spring哪一個參數接收返回值訊息
@AfterReturning(value = "execution(public int com.swj.MyCalculator.*(int,int))",returning = "result")
public static void logReturn(JoinPoint joinPoint, Object result){
System.out.println("["+joinPoint.getSignature().getName()+"] method completed,result is "+result);
}
Advice是由spring透過反射調用,所以需要告訴spring哪一個參數接收exception訊息
@AfterThrowing(value = "execution(public int com.swj.MyCalculator.*(int,int))",throwing = "exception")
public static void logException(JoinPoint joinPoint,Exception exception){
System.out.println("["+joinPoint.getSignature().getName()+"] method throws exception:"+exception.getMessage());
}
@Test
public void testDay20(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean20.xml");
System.out.println("容器啟動完成....");
MyCalculator calculator = ioc.getBean(MyCalculator.class);
calculator.add(1,1);
System.out.println("=================");
calculator.div(1,0);
}
Result