AOP
AOP是Aspect Oriented Programing的简称,面向切面编程,使用场景:如性能监测,访问控制,事务管理、缓存、对象池管理以及日志记录
动态、静态代理区别
动态代理
运行时生成对应的代理class。是通过反射生成对应的代理类。在代理类上下文做相应操作。
- JDK动态代理:
- JDK动态代理只能代理有接口的类,并且是能代理接口方法,不能代理一般的类中的方法。
- 提供了一个使用InvocationHandler作为参数的构造方法。在代理类中做一层包装,业务逻辑在invoke方法中实现。
- 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
- 在invoke方法中我们甚至可以不用Method.invoke方法调用实现类就返回。这种方式常常用在RPC框架中,在invoke方法中发起通信调用远端的接口等
- Cglib动态代理:
- 弥补了java动态代理的缺陷。可以代理非接口和接口。他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强。
但因为采用的是继承,所以不能对final修饰的类进行代理。 - CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类(代理接口需要实现对应的方法).
- 由于是继承方式,如果是 static方法,private方法,final方法等描述的方法是不能被代理的
- 做了方法访问优化,使用建立方法索引的方式避免了传统Method的方法反射调用.
- 提供callback 和filter设计,可以灵活地给不同的方法绑定不同的callback。编码更方便灵活。
- CGLIB会默认代理Object中finalize,equals,toString,hashCode,clone等方法。比JDK代理多了finalize和clone。
静态代理
编译时生成对应的代理class,由于是静态织入的,所以性能相对来说比较好
Spring AOP
Spring AOP 是运行时编译,实现方式有两种 jdk 的 InvocationHandler、proxy 和 Cglib。 Spring代理实际上是对JDK代理和CGLIB代理做了一层封装,并且引入了AOP概念:Aspect、advice、joinpoint等等,同时引入了AspectJ中的一些注解@pointCut,@after,@before等等.Spring Aop严格的来说都是动态代理,所以实际上Spring代理和Aspectj的关系并不大.
AspectJ
- AspectJ的静态代理,它会在编译阶段将Aspect织入Java字节码中, 运行的时候就是经过增强之后的AOP对象。
- AspectJ在编译时就增强了目标对象,Spring AOP的动态代理则是在每次运行时动态的增强,生成AOP代理对象,区别在于生成AOP代理对象的时机不同。
- 相对来说 AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
- Aspectj并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到class文件
- 由于是静态织入的,所以性能相对来说比较好
- Aspectj不受类的特殊限制,不管方法是private、或者static、或者final的,都可以代理
- Aspectj不会代理除了限定方法之外任何其他诸如toString(),clone()等方法

Spring AOP 增强
- @Before 方法执行前增强
- @Around 环绕增强
- @AfterReturning 方法正常结束增强
- @AfterThrowing 异常增强
- @After 返回增强(无论是否执行)
Spring AOP 增强正常执行顺序

Spring AOP 增强异常执行顺序

注意:
1.可以对一个方法执行多个切面。但是顺序是随机的。
2.Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理,如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。使用beanNameAutoProxyCreator来进行事务代理的话,他的proxyTargetClass这个属性设置为false(默认是false),即使用JDK动态代理,如果你的service类没有实现接口的话,就会报类型转换错误 // ClassCastException: $Proxy0 cannot be cast to
BaseJob job = (BaseJob) applicationContext.getBean(taskTimer.getTaskClass());
3.Spring AOP不支持代理类内部方法调用的拦截,比如类中a方法调用b方法,切面拦截b方法会失败的。@Async注解使用注意 (https://blog.csdn.net/quzishen/article/details/5803721)