一、简介
spring AOP⾯向切⾯编程,实则是⼀种思想,是对某类事物的集中处理。通俗来讲,将与核心业务无关的代码独立抽取出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的一种操作理念。
二、spring AOP组成
1、切面(Aspect)
切面通常由切点和通知组成。是独立出来增强功能的集合。
2、连接点(Join Point)
应⽤执⾏过程中能够插⼊切⾯的⼀个点,相当于需要被增强的某个 AOP 功能的所有⽅法。
3、通知(Advice)
相当于需要增强的内容。有五种类型:
- 前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
- 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
- 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
- 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
- 环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。
4、切点(Pointcut )
提供⼀组规则,来匹配 Join Point,给满⾜规则的 Join Point 添加 Advice。相当于保存了众多连接点的⼀个集合
三、使用示例
1、被增强类
@RestController @RequestMapping("/aopTest") public class AopTestController { @GetMapping("test") public void insert() { System.out.println("实际逻辑。。。。。。。。。"); } }
2、增强类
@Aspect @Component public class AopComponent { @Pointcut(value = "execution(* com.example.testaop.controller.AopTestController.*(..))") public void pointCut(){ } @Before(value = "pointCut()") public void before(){ System.out.println("aop增强测试。。。。before。。。。"); } @After(value = "pointCut()") public void after(){ System.out.println("aop增强测试。。。。。after。。。"); } @Around(value = "pointCut()") public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("aop增强测试。。。。。around1。。。"); joinPoint.proceed(); System.out.println("aop增强测试。。。。。around2。。。"); } @AfterReturning(value = "pointCut()") public void afterReturning(){ System.out.println("aop增强测试。。。。。afterReturning。。。"); } @AfterThrowing(value = "pointCut()", throwing = "e") public void afterThrowing(JoinPoint joinPoint, Exception e){ System.out.println("aop增强测试。。。。。afterThrowing。。。"); System.out.println("throwing: "+e.getMessage()); } }
3、测试结果
aop增强测试。。。。。around1。。。
aop增强测试。。。。before。。。。
实际逻辑。。。。。。。。。
aop增强测试。。。。。afterReturning。。。
aop增强测试。。。。。after。。。
aop增强测试。。。。。around2。。。
4、结论
通知的顺序 around -> before -> 实际方法 -> afterReturning -> after -> around
四、spring AOP实现原理
spring AOP是基于动态代理实现的。支持 JDK Proxy 和 CGLIB 两种方式。
1、jdk动态代理
主要由重写InvocationHandle接口的invoke方法和Proxy创建代理实例构成。
1.1、接口
public interface JdkProxy { void testJdkProxy(); }
1.2、实现
public class JdkProxyImpl implements JdkProxy { @Override public void testJdkProxy() { System.out.println("对JdkProxy的实现。。。。。JdkProxyImpl。。。。"); } }
1.3、动态代理处理类
public class MyInvcationHandler implements InvocationHandler { private Object object; public MyInvcationHandler( Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("MyInvcationHandler代理1。。。。。invoke。。。。"); method.invoke(object,args); System.out.println("MyInvcationHandler代理2。。。。。invoke。。。。"); return null; } }
1.4、测试
@GetMapping("test1") public void test1() { JdkProxyImpl jdkProxyImpl = new JdkProxyImpl(); MyInvcationHandler myInvcationHandler = new MyInvcationHandler(jdkProxyImpl); JdkProxy jdkProxy = (JdkProxy) Proxy.newProxyInstance(jdkProxyImpl.getClass().getClassLoader(), jdkProxyImpl.getClass().getInterfaces(), myInvcationHandler); jdkProxy.testJdkProxy(); }
1.5、结论
MyInvcationHandler代理1。。。。。invoke。。。。
对JdkProxy的实现。。。。。JdkProxyImpl。。。。
MyInvcationHandler代理2。。。。。invoke。。。。
2、cglib动态代理
重写需被增强类的方法,子类通过传递方法拦截器Methodlnterceptor实现方法拦截,并在intercept中做具体增强。
2.1、cglib增强
public class CglibProxyImpl implements MethodInterceptor { private Object object; public Object getInstance(Object object) { this.object = object; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.object.getClass()); // 设置回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib增强1。。。。。intercept。。。。。"); methodProxy.invokeSuper(o,objects); System.out.println("cglib增强2。。。。。intercept。。。。。"); return null; } }
2.2、测试
@GetMapping("test2") public void test2() { CglibProxyImpl cglibProxy = new CglibProxyImpl(); JdkProxyImpl cglibProxyInstance = (JdkProxyImpl) cglibProxy.getInstance(new JdkProxyImpl()); cglibProxyInstance.testJdkProxy(); }
2.3、结论
cglib增强1。。。。。intercept。。。。。
对JdkProxy的实现。。。。。JdkProxyImpl。。。。
cglib增强2。。。。。intercept。。。。。
3、两者区别
jdk代理适用于代理接口类型的;cglib代理适用于代理类类型的。
jdk代理基于Java反射机制实现;cglib不是。
jdk代理无需引用第三方库,jdk自带;cglib需要依赖