(七)Spring AOP - 原理简介
(八)Spring AOP - 核心概念简介
(九)Spring AOP - 简单配置
1. 切点表达式
共分两类:
- within表达式
通过类名匹配,粗粒度切点表达式
语法:within(包名.类名) - execution表达式(最常用)
以方法为单位切入匹配,细粒度切点表达式
语法:execution(返回值类型 包名.类名.方法名(参数类型,参数类型…))
可以使用 &&, || 和 !等符号进行合并操作//&&:两个表达式同时 execution( public int com.lazy.proxy.dynamic.Calculator.*(..)) && execution(* *.*(int,int) ) //||:任意满足一个表达式即可 execution( public int com.lazy.proxy.dynamic.Calculator.*(..)) && execution(* *.*(int,int) ) //!:只要不是这个位置都可以进行切入 //&&:两个表达式同时 execution( public int com.lazy.proxy.dynamic.Calculator.*(..))
2. @Pointcut抽取切点
为之前写的计算器写个切面增强
@Pointcut("execution(* com.lazy.proxy.dynamic.Calculator.*(..) )")
public void point() {
}
@Before("point()")
3. 获取执行方法详细信息
@Component
@Aspect
public class CalculatorAspect {
@Pointcut("execution(* com.lazy.proxy.dynamic.Calculator.*(..) )")
public void point() {
}
@Before("point()")
public void before(JoinPoint joinPoint) {
System.out.println("****************方法执行前*****************");
String methodName = joinPoint.getSignature().getName();
System.out.println("---方法名:" + methodName);
Object[] args = joinPoint.getArgs();
System.out.println("---参数是:" + Arrays.asList(args));
}
@AfterReturning(value = "point()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("****************方法执行返回*****************");
String methodName = joinPoint.getSignature().getName();
System.out.println("---方法名:" + methodName);
System.out.println("---方法执行完成,返回值是:" + result);
}
@AfterThrowing(value = "point()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("****************方法执行异常*****************");
String methodName = joinPoint.getSignature().getName();
System.out.println("---方法名:" + methodName);
System.out.println("---方法执行异常,异常是:" + ex.getMessage());
}
@After(value = "point()")
public void after(JoinPoint joinPoint) {
System.out.println("****************方法执行完成*****************");
String methodName = joinPoint.getSignature().getName();
System.out.println("---方法名:" + methodName);
}
}
4. 通知方法的执行顺序
正常执行:@Before—>@AfterReturning—>@After
@Test
public void testAfterReturning() {
ICalculator calculator = context.getBean(ICalculator.class);
int sum = calculator.sum(3, 5);
System.out.println("---sum结果:" + sum);
}
Test:
异常执行:@Before—>@AfterThrowing—>@After
@Override
public int sub(int numA, int numB) throws Exception {
if (numA < 0) {
throw new Exception("不能小于0");
}
int result = numA - numB;
return result;
}
@Test
public void testAfterThrowing() {
ICalculator calculator = context.getBean(ICalculator.class);
int sum = 0;
try {
sum = calculator.sub(-1, 5);
} catch (Exception e) {
//e.printStackTrace();
}
System.out.println("---sum结果:" + sum);
}
Test:
5. 环绕通知,最强大的通知,需要自己调用执行方法
/**
* @Description: 环绕通知
*/
@Around(value = "point()")
public Object around(ProceedingJoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
Object proceed = null;
try {
System.out.println("########## 方法环绕前置通知,方法名:" + methodName + " ##### 参数:" + Arrays.asList(args));
//利用反射调用目标方法,就是method.invoke()
proceed = joinPoint.proceed(args);
System.out.println("########## 方法环绕后置返回通知,返回值:" + proceed );
} catch (Throwable throwable) {
System.out.println("########## 方法环绕后置异常通知,返回值:" + throwable.getMessage() );
} finally {
System.out.println("########## 方法环绕后置通知,方法名:" + methodName );
}
return proceed;
}
Test:
环绕通知方法有返回值,不写返回值可能会抛出异常
org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for
6. xml配置
<bean id="calculatorAspect" class="com.lazy.aspect.CalculatorAspect"></bean>
<aop:config>
<aop:pointcut id="globalPoint" expression="execution(* com.lazy.proxy.dynamic..*(..))"/>
<aop:aspect ref="calculatorAspect">
<aop:pointcut id="mypoint" expression="execution(* com.lazy.proxy.dynamic..*(..))"/>
<aop:before method="before" pointcut-ref="mypoint"></aop:before>
<aop:after method="after" pointcut-ref="mypoint"></aop:after>
<aop:after-returning method="afterReturning" pointcut-ref="mypoint" returning="result"></aop:after-returning>
<aop:after-throwing method="afterThrowing" pointcut-ref="mypoint" throwing="ex"></aop:after-throwing>
<aop:around method="around" pointcut-ref="mypoint"></aop:around>
</aop:aspect>
</aop:config>