• Spring对AOP的实现


    Spring对AOP实现的模式分为2种,一种是代理,一种是AspectJ,这种区分方式是直接使用实现方式区分的。

    一、Spring对动态代理的设计

    动态代理我们都知道在Spring中分为JDK动态代理和cglib动态代理,JDK动态代理自不用说,由Java运行时环境提供,而对于cglib,Spring将他封装在了spring-core中,足以证明动态代理在Spring中处于一个基础+核心的地位,所以我们更加有必要搞清楚Spring是如何使用cglib的,而对于Spring AOP而言,则是单独的作为一个模块出现:spring-aop。

    使用jdk动态代理,是通过生成一个实现了接口的代理类,代理类中包含原始类,被增强的方法不是直接写好了各种增强逻辑,而是通过Advisor列表组合好,依次调用。使用cglib动态代理,是通过生成一个继承目标类的代理类,代理类中包含原始类,被增强的方法也不是直接生成各种代理逻辑,同样是通过Advisor列表进行动态调用。

    二、2种动态代理的特点

    JDK动态代理需提供接口,代理类实现的是接口中的方法,如果无法提供目标对象的接口,无法完成代理。
    cglib通过继承目标类,所以无法目标类为final时无法代理,目标类中方法为final或private时无法代理。
    JDK通过反射实时生成代理对象,cglib通过操作字节码生成代理对象,cglib动态代理会较JDK动态代理快。

    三、AOP联盟的标准

    先来看看spring-aop包的结构:



    其中aopalliance是对AOP和Java有浓厚兴趣的软件开发人员联合成立的开源项目,Spring是按照AOP联盟的规范做的实现,可见Spring是一个集众多基础框架于一身的伟大软件。aopalliance包里面只有接口,没有任何实现,这就是一个规范定义。

    AOP联盟定义的顶级概念有:
    org.aopalliance.aop.Advice
    org.aopalliance.intercept.Joinpoint
    aop联盟中定义分为aop包和intercept,我们可以从这里看出aop联盟对切面的理解。advice是切面的逻辑,是切面中最直观的一个概念,其他的都是为advice服务的。
    org.aopalliance.aop.Advice
    aop联盟定义的advice是一个空接口,起到超类类型标记的作用。Advice是AOP在某个Joinpoint的处理逻辑。

    1. /**
    2. * Tag interface for Advice. Implementations can be any type
    3. * of advice, such as Interceptors.
    4. *
    5. * @author Rod Johnson
    6. * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
    7. */
    8. public interface Advice {
    9. }

    org.aopalliance.intercept.Interceptor
    Interceptor和Advice一样,也是一个空接口,起到超类类型标记的作用,但是他继承了Advice,所以aop联盟的设计是Interceptor只是Advice的实现之一(采用拦截器方式),预留了其他实现的余地。

    1. public interface Interceptor extends Advice {
    2. }

     org.aopalliance.intercept.Joinpoint
    从实现里可以重新对连接点有一个认识,连接点不是一个点,是一种类型。所以连接点包含proceed()方法推进到拦截链上的下一个拦截器。getThis()方法返回持一个对象,这个对象持有当前连接点静态部分,如invocation的目标对象。getStaticPart()返回连接点的静态部分。真的很抽象。

    1. public interface Joinpoint {
    2. /**
    3. * Proceed to the next interceptor in the chain.
    4. *

      The implementation and the semantics of this method depends

    5. * on the actual joinpoint type (see the children interfaces).
    6. * @return see the children interfaces' proceed definition
    7. * @throws Throwable if the joinpoint throws an exception
    8. */
    9. Object proceed() throws Throwable;
    10. /**
    11. * Return the object that holds the current joinpoint's static part.
    12. *

      For instance, the target object for an invocation.

    13. * @return the object (can be null if the accessible object is static)
    14. */
    15. Object getThis();
    16. /**
    17. * Return the static part of this joinpoint.
    18. *

      The static part is an accessible object on which a chain of

    19. * interceptors are installed.
    20. */
    21. AccessibleObject getStaticPart();
    22. }

     org.aopalliance.intercept.Invocation

    1. public interface Invocation extends Joinpoint {
    2. /**
    3. * Get the arguments as an array object.
    4. * It is possible to change element values within this
    5. * array to change the arguments.
    6. * @return the argument of the invocation
    7. */
    8. Object[] getArguments();
    9. }

    Spring对AOP的设计如下:

    Spring定义的顶级概念有:
    org.springframework.aop.Advisor
    org.springframework.aop.Pointcut
    aop联盟没有切点的概念,只有连接点,切点描述的是被切的目标,如哪些方法,连接点描述的是目标被切的位置,如方法的前后。换句话说,aop联盟定义了能切目标,不关心用户要切目标中的哪一些。aop联盟定义的概念还是更加抽象,Spring定义的概念更加贴近实现。

    org.aopalliance.aop.Advice

    顶级接口增强,建议,也就是要添加的代理逻辑所在位置,Advice处于设计的高层,他会使用Joinpoint
    AOP联盟和Spring对Advice的设计如下,可以看出,对ConstructorInterceptor大家一点兴趣也没有,没有人对构造方法处理,BeforeAdvice和AfterAdvice的功能也可以被

    org.aopalliance.intercept.Joinpoint

    顶级接口连接点,是调用代理逻辑的位置,注意不是代理逻辑所在位置,可以是构造方法,普通方法,字段等,我们通常使用的是方法。所以Joinpoint中有个重要方法proceed(),意思是继续处理。
    AOP联盟对Joinpoint的设计如下,看的出来,连接点的子接口就是调用,调用又分为构造方法调用和普通方法调用。

    MethodInterceptor里的重要方法是:Object invoke(MethodInvocation invocation) throws Throwable;
    MethodInvocation里的重要方法是继承Joinpoint的:Object proceed() throws Throwable;
    我们如果要开发框架,通常会继承MethodInterceptor,它像是个钩子,会被回调,代表代理的逻辑。
    MethodInvocation通常是被动态代理框架实现,比如cglib,他会去实现里面的proceed()方法。
    注意MethodInterceptor会使用MethodInvocation,MethodInterceptor是设计的高层。
    以上是AOP联盟对AOP规范的定义。

    五、Spring在AOP联盟基础上对AOP的设计

    1、代理对象生成方式的设计
    Spring AOP在动态代理方式的设计如下:
    org.springframework.aop.framework.AopProxy
    这个接口定义的是动态代理生成的方式,开箱即用的实现有2个,分别是cglib和JDK dynamic proxies,我们也可以看到实现类为:
    org.springframework.aop.framework.JdkDynamicAopProxy
    org.springframework.aop.framework.CglibAopProxy
    具体实现我们这里不看了

    2、生成动态代理对象
    org.springframework.aop.framework.ProxyFactoryBean
    这里有个ProxyCreatorSupport容易被忽视,但是他是非常重要的一个类
    无论是getSingletonInstance()还是newPrototypeInstance()最后都调用了一个createAopProxy(...),这个方法创建代理方式的,一般返回JdkDynamicAopProxy或CglibAopProxy,但是这个我们并不太关心,知道就行了。
    getObject()方法是获取代理对象的方法,里面根据情况调用getSingletonInstance()或newPrototypeInstance()方法
    这两个方法最终会调用createAopProxy(),虽然这个方法是生成一个一个AopProxy实例,但是这个AopProxy实例是对应着一个具体的客户代理实例,所以里面需要处理很多客户代理的信息
    关键是createAopProxy()方法将ProxyCreatorSupport类作为参数传递进去了,也就是说,生成代理实例的时候肯定需要使用ProxyCreatorSupport类。

    1. @SuppressWarnings("serial")
    2. public class ProxyFactoryBean extends ProxyCreatorSupport
    3. implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware {
    4. ...
    5. @Override
    6. @Nullable
    7. public Object getObject() throws BeansException {
    8. initializeAdvisorChain();
    9. if (isSingleton()) {
    10. return getSingletonInstance();
    11. }
    12. else {
    13. if (this.targetName == null) {
    14. logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
    15. "Enable prototype proxies by setting the 'targetName' property.");
    16. }
    17. return newPrototypeInstance();
    18. }
    19. }
    20. private synchronized Object getSingletonInstance() {
    21. if (this.singletonInstance == null) {
    22. this.targetSource = freshTargetSource();
    23. if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
    24. // Rely on AOP infrastructure to tell us what interfaces to proxy.
    25. Class targetClass = getTargetClass();
    26. if (targetClass == null) {
    27. throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
    28. }
    29. setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    30. }
    31. // Initialize the shared singleton instance.
    32. super.setFrozen(this.freezeProxy);
    33. this.singletonInstance = getProxy(createAopProxy());
    34. }
    35. return this.singletonInstance;
    36. }
    37. private synchronized Object newPrototypeInstance() {
    38. // In the case of a prototype, we need to give the proxy
    39. // an independent instance of the configuration.
    40. // In this case, no proxy will have an instance of this object's configuration,
    41. // but will have an independent copy.
    42. ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
    43. // The copy needs a fresh advisor chain, and a fresh TargetSource.
    44. TargetSource targetSource = freshTargetSource();
    45. copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
    46. if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
    47. // Rely on AOP infrastructure to tell us what interfaces to proxy.
    48. Class targetClass = targetSource.getTargetClass();
    49. if (targetClass != null) {
    50. copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    51. }
    52. }
    53. copy.setFrozen(this.freezeProxy);
    54. return getProxy(copy.createAopProxy());
    55. }
    56. protected final synchronized AopProxy createAopProxy() {
    57. if (!this.active) {
    58. activate();
    59. }
    60. return getAopProxyFactory().createAopProxy(this);
    61. }
    62. ...
    63. }
    64. 3、org.springframework.aop.framework.ProxyCreatorSupport的作用
      ProxyCreatorSupport本身的逻辑很简单,100多行代理而已,都是些封装一层的逻辑而已。关键是他的父类:

      1. public class ProxyCreatorSupport extends AdvisedSupport {
      2. ...
      3. }

      4、org.springframework.aop.framework.AdvisedSupport
      这个类是一个支持类,非常关键,里面有一个advisors成员,是Advisor列表,我们知道Advice是代理逻辑所在类,而Advisor是Advice的承载类,所以可以很明确的知道,AdvisedSupport类是生成代理的基础材料,因为他包含了所有的代理逻辑
      这里的命名是Advised,有几个类的作用是必须要澄清的
      org.springframework.aop.framework.Advised
      org.springframework.aop.Advisor
      org.aopalliance.aop.Advice
      Advised使用Advisor,Advisor使用Advice,其实Advisor和Advice是一个一对一的关系,Advisor是Advice的一层封装

      1. public class AdvisedSupport extends ProxyConfig implements Advised {
      2. ...
      3. private List advisors = new ArrayList<>();
      4. ...
      5. }

    65. 相关阅读:
      学习Spring5必知必会(4)~使用注解配置、使用java代码配置
      设计模式——模板方法模式
      密码学 aes rsa 分段加密 填充 rsakey 生成
      NAACL2022信息抽取论文分类
      Hugging Face LLM部署大语言模型到亚马逊云科技Amazon SageMaker推理示例
      Java新特性(2):Java 10以后
      【数据结构】二叉树的层序遍历~动画超详解
      计算机网络第三章 数据链路层
      信安软考——第七章 访问控制技术原理与应用
      MYSQL数据库管理与创建
    66. 原文地址:https://blog.csdn.net/tales522/article/details/128163957