1. 說明
AOP能夠給組件創建代理類,在目標類的方法的前後,異常等位置織入自定義代碼,到達方法增強的目的;
2. 步驟
2.1 編寫業務類;
2.2 編寫業務切面類,在目標業務類的目標方法的適當位置(方法之前、方法運行結束、方法出現異常)編寫自定義代碼;
通知方法:
前置通知(@Before):在目標方法運行之前運行
後置通知(@After)::在目標方法運行結束之後運行(無論方法正常結束還是異常結束)
返回通知(@AfterReturning):在目標方法(div)正常返回之後運行
異常通知(@AfterThrowing):在目標方法(div)出現異常以後運行
環繞通知(@Around):動態代理,手動推進目標方法運行(joinPoint.procced())
2.3 給切面類的目標方法標註何時何地運行(通知註解);
2.4 將切面類和業務邏輯類(目標方法所在類)都加入到容器中;
2.5 給配置類中加 @EnableAspectJAutoProxy 【開啓基於註解的aop模式】
3. 例子
- 3.1 業務類
package com.yibai.spring.annotation.aop;
public class Calculator {
public int div(int a, int b) {
return a / b;
}
}
- 3.2 業務切面類
package com.yibai.spring.annotation.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CalculatorAspect {
@Pointcut(value = "execution(public int com.yibai.spring.annotation.aop.Calculator.*(..))")
public void pointCutCalculator() {
}
@Before("pointCutCalculator()")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@Before ... 方法名: " + methodName + ", 方法參數: " + Arrays.asList(args));
}
@After("pointCutCalculator()")
public void after(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@After ... 方法名: " + methodName + ", 方法參數: " + Arrays.asList(args));
}
// returning: 接收返回值
@AfterReturning(value = "pointCutCalculator()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println(
"@AfterReturning ... 方法名: " + methodName + ", 方法參數: " + Arrays.asList(args) + ", 正常返回值: " + result);
}
// throwing: 接收異常信息
@AfterThrowing(value = "pointCutCalculator()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@AfterThrowing ... 方法名: " + methodName + ", 方法參數: " + Arrays.asList(args) + ", 異常信息: " + e);
}
}
- 3.3 主配置類
package com.yibai.spring.annotation.main.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.yibai.spring.annotation.aop.Calculator;
import com.yibai.spring.annotation.aop.CalculatorAspect;
@EnableAspectJAutoProxy //開啓基於註解的aop模式
public class MainConfigForAop {
@Bean
public Calculator calculator() {
return new Calculator();
}
@Bean
public CalculatorAspect calculatorAspect() {
return new CalculatorAspect();
}
}
- 3.4 啓動類
package com.yibai.spring.annotation.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.yibai.spring.annotation.aop.Calculator;
import com.yibai.spring.annotation.main.config.MainConfigForAop;
/**
* Hello world!
*
*/
public class MainClass {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
MainConfigForAop.class);
Calculator calculator = applicationContext.getBean(Calculator.class);
System.out.println("結果: " + calculator.div(10, 2));
applicationContext.close();
}
}
- 3.5 運行打印結果
@Before ... 方法名: div, 方法參數: [10, 2]
@After ... 方法名: div, 方法參數: [10, 2]
@AfterReturning ... 方法名: div, 方法參數: [10, 2], 正常返回值: 5
結果: 5
當運行 10/0 的打印結果
@Before ... 方法名: div, 方法參數: [10, 0]
@After ... 方法名: div, 方法參數: [10, 0]
@AfterThrowing ... 方法名: div, 方法參數: [10, 0], 異常信息: java.lang.ArithmeticException: / by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.yibai.spring.annotation.aop.Calculator.div(Calculator.java:6)
at com.yibai.spring.annotation.aop.Calculator$$FastClassBySpringCGLIB$$ef7d340d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.yibai.spring.annotation.aop.Calculator$$EnhancerBySpringCGLIB$$bcd84541.div(<generated>)
at com.yibai.spring.annotation.main.MainClass.main(MainClass.java:57)