一、AOP
1. 简介
Aspect Oriented Programming: 面向切面编程
在不改变源码的基础上,实现对原有代码的增强
连接点: 类中可以被增强的方法
切入点: 类中实际被增强的方法
通知: 实际增强的额外逻辑部分称为通知,(前置,后置,环绕,异常,最终通知)
切面: 把通知应用到切入点的过程称为切面
独立于spring,是一个AOP 的具体实现方法
pom: aspectjweaver
根据具体的类可以自动切换 JDK代理和CGLib 代理
二、AspectJ实现
1. 主配置类
package com.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@ComponentScan(basePackages = "com.aop")
@EnableAspectJAutoProxy
public class AOPConfig {
}
2. 业务类
- 会根据业务类是基于接口还是基于子类,动态切换JDK动态代理还是Cglib动态代理
package com.aop;
import org.springframework.stereotype.Component;
@Component
public class VendorService {
public void work() {
System.out.println("工作");
}
public void sleep() {
System.out.println("睡觉");
}
public void eat() {
int num = 1 / 0;
System.out.println("吃饭");
}
public String play() {
System.out.println("玩耍");
return "soccer";
}
}
3. 通知类
package com.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AspectProxy {
@Before(value = "execution(* com.aop.VendorService.work(..) )")
public void before() {
System.out.println("前置工作");
}
@After(value = "execution(* com.aop.VendorService.work(..) )")
public void after() {
System.out.println("后置工作");
}
@Around(value = "execution(* com.aop.VendorService.sleep(..) )")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前工作");
proceedingJoinPoint.proceed();
System.out.println("环绕后工作");
}
@AfterThrowing(value = "execution(* com.aop.VendorService.eat(..) )")
public void afterThrowing() {
System.out.println("抛出错误");
}
@AfterReturning(value = "execution(* com.aop.VendorService.play(..) )", returning = "result")
public void afterReturning(Object result) {
System.out.println(result);
System.out.println("返回结果的后置方法");
}
}
三、 通知优化
1. 切入点表达式抽取
package com.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AspectProxy {
@Pointcut(value = "execution(* com.aop.VendorService.eat(..) )")
public void servicePoint() {
}
@Before(value = "servicePoint()")
public void afterEat() {
System.out.println("吃饭后置工作");
}
@After(value = "servicePoint()")
public void afterPlay() {
System.out.println("吃饭前工作");
}
}
2. 通知优先级
package com.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)
public class AspectProxy {
@Before(value = "execution(* com.aop.VendorService.eat(..) )")
public void afterEat() {
System.out.println("第一个吃饭前置工作");
}
}
@Component
@Aspect
@Order(2)
class AspectProxySecond {
@Before(value = "execution(* com.aop.VendorService.eat(..) )")
public void afterEat() {
System.out.println("第二个吃饭前置工作");
}
}