Spring之AOP满满的干货

动态AOP使用示例

  1. 先创建用于拦截的bean
  2. 创建Advisor
  3. 创建配置文件
  4. 测试

spring是如何实现AOP的呢?首先我们从spring的配置文件aop:aspectj入手。通过前面的了解,我们知道在某个地方注册了解析器。于是在BeanDefinitionParser中找到了入口函数parse()。parse函数调用了注册自动代理创建器。注册代理创建器主要完成了三件事:

  1. 注册或者升级自动代理创建器,同时这里还涉及了一份优先级的问题,如果已经存在了自动代理创建器,而且存在的自动代理创建器与现在的不一致,那么就需要根据优先级判断到底需要使用哪个。
  2. 处理proxy-target-class以及expose-proxy属性。

proxy-target-class:springAOP部分使用的是jdk动态代理或者CGLIB来为目标对象创建代理(建议尽量使用jdk的动态代理),如果被代理的目标对象实现了至少一个接口,则会使用jdk动态代理,所有该目标类型实现的接口都将被代理。若该目标对象没有实现任意接口,则会创建一个CGLIB代理。如果你希望强制使用CGLIB代理,你需要考虑两个问题。

  • 1)无法通知Final方法,因为他们不能被复写;
  • 2)你需要将CGLIB二进制放在classpath下面;
  • JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。

CGLIB代理:它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB代理是高效的代码生成包,底层是依靠ASM操作字节码实现的,性能比jdk强。

  • 3)注册组件通知,便于监听器做进一步处理。
  1. 接下来便到了AOP的核心了。

创建代理主要包含两个步骤:

  1. 获取增强方法或者增强器。
  2. 根据获取的增强进行代理。

我详细讲解一下这两个方法吧

在实现获取增强的方法中除了保留父类的配置文件定义的增强外,同时添加了获取Bean的注解增强功能。首先获取所有beanName,这一步骤中所有在beanFactory中注册的Bean都会被提取出来,放在list集合中。接着开始遍历所有的beanName,并找出声明AspectJ注解的类,进行进一步处理。然后对标记为AspectJ注解的类进行增强器的提取,最后将提取结果加入到缓存中。这是获取增强器的四个主要步骤。

这四个步骤又可以细分比如创建通知类时先要获取切点信息像@Before这类切入点,然后再根据切点信息生成增强,这里只是将信息封装在类的实例中。最后根据不同的注解类型封装不同的增强器。这时候我们已经找到相匹配的增强器了。这时已经到了两个步骤的最后一步

。在获取了所有对应bean的增强器后,便可以进行代理的创建了。对于代理类的创建及处理,Spring委托给了ProxyFactory去处理,ProxyFactory是对真正创建代理类做准备的,这里面还包括了获取当前类的属性,添加代理接口,接着封装Advisor并加入到ProxyFactory中然后设置要代理的类,最后就是获取代理类操作了。这里有两种代理类进行选择。一种就是jdk动态代理,另一种就是CGLIB代理。这里我就不解释这两种代理对象了。JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。(开始的时候说过了)

CGLIB代理:它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB代理是高效的代码生成包,底层是依靠ASM操作字节码实现的,性能比jdk强。

我就对jdk和CGLIB方式总结一下:

如果目标对象实现了接口,默认情况下会采用jdk的动态代理实现AOP。

如果目标对象实现了接口,可以强制使用CGLIB实现AOP。

若果目标对象没有实现接口,必须采用CGLIB库,Spring会自动在jdk动态代理和CGLIB代理之间转化。

jdk动态代理和CGLIB字节码生成的区别:

jdk动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承关系,所以该类或方法最好不要生明成Final。

你可能感兴趣的:(Spring源码系列)