首页 > 编程语言 >Spring源码(14) -- Aop动态代理CglibAopProxy

Spring源码(14) -- Aop动态代理CglibAopProxy

时间:2024-10-04 11:12:16浏览次数:8  
标签:enhancer 14 -- Object 代理 CglibAopProxy 源码 proxy advised

AOP基础知识

AOP基础知识,详情见: https://blog.csdn.net/sinat_32502451/article/details/142291052

AOP 源码,详情见: https://blog.csdn.net/sinat_32502451/article/details/142291110

AopProxy

AopProxy 接口是配置的AOP代理的委托接口,允许创建实际的代理对象。
开箱即用的实现可用于 JDK 动态代理和 CGLIB 代理 。

public interface AopProxy {

	/**
	 * 创建新的代理对象。使用AopProxy的默认类加载器(如果需要创建代理):通常是线程上下文类加载器。
	 */
	Object getProxy();

	/**
	 * 创建新的代理对象。使用给定的类加载器(如果需要创建代理)。
	 */
	Object getProxy(@Nullable ClassLoader classLoader);

}

CglibAopProxy

代码: org.springframework.aop.framework.CglibAopProxy

CglibAopProxy 是 Spring AOP框架的基于CGLIB的AopProxy实现。
CglibAopProxy 实现了 AopProxy。
此类对象应通过代理工厂获得,由AdvisedSupport对象配置。这个类是Spring的AOP框架的内部,不需要由客户端代码直接使用。
DefaultAopProxyFactory将在必要时自动创建基于CGLIB的代理,例如在代理目标类的情况下。

Enhancer

源码:net.sf.cglib.proxy.Enhancer

Enhancer 是标准Jdk动态代理的替代品,用于生成动态子类以启用方法拦截,还允许代理扩展具体的基类。
Aop Cglib动态代理,会运用到 Enhancer、Callback、CglibAopProxy、MethodInterceptor、MethodProxy 等等。

Callback 接口

源码: org.springframework.cglib.proxy.Callback

被 net.sf.cglib.proxy.Enhancer 类调用的回调接口都会继承 Callback 接口。

public interface Callback {
}

MethodInterceptor

源码:org.springframework.cglib.proxy.MethodInterceptor

MethodInterceptor 继承了 Callback接口。参数包含 对象,方法,上面说过的 MethodProxy 等。
AOP中经常用来实现拦截方法的调用。

public interface MethodInterceptor extends Callback {
    Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}

Cglib动态代理示例:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;

public class CglibProxyDemo {

    public static class Target {
        public void printHello() {
            System.out.println("Hello World");
        }
    }

    public static void main(String[] param) {
        //Enhancer 是标准Jdk动态代理的替代品,用于生成动态子类以启用方法拦截,还允许代理扩展具体的基类。
        Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args, methodProxy) -> {
            System.out.println("before method.");
            
            //以下 p的值是 com.example.demo.sourceCode.cglib.CglibDemo$Target$$EnhancerByCGLIB$$87c3a731@27c60c
            // methodProxy的 fastClassInfo 有 f1为 class com.example.demo.sourceCode.cglib.CglibDemo$Target, 
            // f2为class com.example.demo.sourceCode.cglib.CglibDemo$Target$$EnhancerByCGLIB$$87c3a731
            
            Object result = methodProxy.invokeSuper(p, args);  
            System.out.println("after method.");
            return result;
        });

        proxy.printHello();

    }

}

MethodProxy的 invokeSuper

MethodProxy的作用:当调用被拦截的方法时,Enhancer 生成的类会将此对象传递给已注册的 MethodInterceptor(方法拦截器) 对象。
它既可以用来调用原始方法,也可以在同一类型的不同对象上调用相同的方法。

源码: org.springframework.cglib.proxy.MethodProxy#invokeSuper

  /**
  *  调用指定对象上的原始方法。
  */
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
          //实例化成员变量 fastClassInfo,包含了类及方法名称等属性。
            init();
            FastClassInfo fci = fastClassInfo;
            //调用方法
            return fci.f2.invoke(fci.i2, obj, args);
        }
        catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
    
      /*
         *  实例化 fastClassInfo.
         */
        private void init() {
          if (fastClassInfo == null) {
              synchronized (initLock) {
                  if (fastClassInfo == null) {
                      CreateInfo ci = createInfo;
  
                      FastClassInfo fci = new FastClassInfo();
                      fci.f1 = helper(ci, ci.c1);
                      fci.f2 = helper(ci, ci.c2);
                      fci.i1 = fci.f1.getIndex(sig1);
                      fci.i2 = fci.f2.getIndex(sig2);
                      fastClassInfo = fci;
                      createInfo = null;
                  }
            }
        }
    }

CglibAopProxy 生成代理对象

CglibAopProxy 生成代理对象的源码,比较核心。可以重点看看。

源码: org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)

    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }

        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            Class<?> proxySuperClass = rootClass;
            //判断是否为 Cglib动态代理。
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            validateClassIfNecessary(proxySuperClass, classLoader);

            // 创建 enhancer, 配置CGLIB增强器。
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

            //获取  Callback数组。
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
           
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            //设置回调数组的Class类型
            enhancer.setCallbackTypes(types);

            // 生成代理类并创建代理实例。
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException | IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                    ": Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Throwable ex) {
            //AOP异常
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }
    
    
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
          enhancer.setInterceptDuringConstruction(false);
          //enhancer 设置回调数组 callbacks
          enhancer.setCallbacks(callbacks);
          //创建代理对象
          return (this.constructorArgs != null && this.constructorArgTypes != null ?
                  enhancer.create(this.constructorArgTypes, this.constructorArgs) :
                  enhancer.create());
    }

CglibAopProxy.DynamicAdvisedInterceptor

DynamicAdvisedInterceptor 是 CglibAopProxy的内部类。
通用AOP回调。当目标是动态的或代理未冻结时使用。

在 AOP 进行前置/后置通知,需要在目标方法在前后处理逻辑时,就会调用 CglibAopProxy.DynamicAdvisedInterceptor 的 intercept 方法。

源码: org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

        private final AdvisedSupport advised;

        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }

        @Override
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            TargetSource targetSource = this.advised.getTargetSource();
            try {
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // 获取目标对象
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;


                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                }
                else {
                    // 核心方法,重点看看。 创建一个方法调用
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                // 返回值
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
}

CglibMethodInvocation

CglibMethodInvocation 是 CglibAopProxy 的内部类。

CglibMethodInvocation 是 使用AOP代理的AOP方法调用的实现。

在需要调用 代理对象,进行方法调用时,就会使用 CglibMethodInvocation。

源码: org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#CglibMethodInvocation

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        private final MethodProxy methodProxy;

        private final boolean publicMethod;

        public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
                Object[] arguments, @Nullable Class<?> targetClass,
                List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
            this.methodProxy = methodProxy;
            this.publicMethod = Modifier.isPublic(method.getModifiers());
        }

 
        @Override
        protected Object invokeJoinpoint() throws Throwable {
            if (this.publicMethod) {
                return this.methodProxy.invoke(this.target, this.arguments);
            }
            else {
                return super.invokeJoinpoint();
            }
        }
    }

ProxyMethodInvocation

代码:org.springframework.aop.ProxyMethodInvocation

允许访问方法调用所使用的代理。

public interface ProxyMethodInvocation extends MethodInvocation {

    /**
     * 返回此方法调用所通过的代理。
     */
    Object getProxy();

    /**
     * 创建此对象的克隆。
     */
    MethodInvocation invocableClone();

    /**
     * 创建此对象的克隆。
     */
    MethodInvocation invocableClone(Object... arguments);

    /**
     * 设置此链中任何 Advice 中后续调用时使用的参数。
     */
    void setArguments(Object... arguments);

    /**
     * 将具有给定值的指定用户属性添加到此调用中。
     */
    void setUserAttribute(String key, @Nullable Object value);

    /**
     * 返回指定用户属性的值。
     */
    @Nullable
    Object getUserAttribute(String key);

}

标签:enhancer,14,--,Object,代理,CglibAopProxy,源码,proxy,advised
From: https://www.cnblogs.com/expiator/p/18446434

相关文章

  • Spring源码(15) -- Aop动态代理之 Enhancer
    Enhancer用途Enhancer(增强器)是标准Jdk动态代理的替代品,用于生成动态子类以启用方法拦截,还允许代理扩展具体的基类。原始且最通用的回调类型是MethodInterceptor(方法拦截器)。通常,每个Enhancer都会使用一个Callback回调,但可以使用callbackFilter控制每个方法使用哪......
  • [题解]SFMOI Round I A~C
    Portal:https://www.luogu.com.cn/contest/179008\(\bf{100+50+50+25+5=\color{indianred}225\color{black}\,\rk.\184}\)A-StrangeCakeGame显然对于小W,向下移动蛋糕刀是最有利的;对于小M,向右移动是最有利的。所以双方以最佳状态移动,最终\(x\ley\)的巧克力是小W的。直接......
  • Vue3的项目搭建
    有两种方式可以搭建:一:使用vue-cli中的webpack创建 第二:推荐使用vite来创建项目vite是新一代前端构建工具,新的前端构建工具,比webpack要快一些。npmcreatevue@latest创建完项目后,我们可以看到项目最外层有index.htmlVite项目中,index.html是项目的入口文件,在项目最外层。......
  • 完全私有化部署!一款开源轻量级网站防火墙!
    大家好,我是Java陈序员。今天,给大家介绍一款开源轻量级网站防火墙!关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。项目介绍SamWaf——是一款适用于小公司、工作室和个人网站的开源轻量级网站防火墙,完全私有化部署,数据加密且仅......
  • qwq
    呃呃呃这是赛时自以为AK(实际可能四个题全假)后挂着拍子没事干随便写点。呃呃呃正序开题,t1只会暴力dp啊,很不牛。看t2,哦好典,我会了。看t3,哦数论,不会了。写掉t2,发现题面写了坨什么玩意,发了一堆提问没人回。回去看t1,哦哦哦原来数据范围还可以这么写啊,会了然后写了,此时差不多......
  • 11-网络物理隔离技术原理与应用
    11.1概述1)概念目的:既能满足内外网信息及数据交换需求,又能防止网络安全事件出现基本原理:避免两台计算机之间直接的信息交换以及物理上的连通,以阻断两台计算机之间的直接在线网络攻击2)风险网络非法外联U盘摆渡攻击网络物理隔离产品安全隐患针对物理隔离的攻击新方法利用......
  • 华为OD机试真题---整数对最小和
    题目描述给定两个整数数组array1和array2,数组元素按升序排列。假设从array1和array2中分别取出一个元素可构成一对元素。现在需要取出K个元素对(即从两个数组中各取一个元素组成一个对,共取K个这样的对),并对取出的所有元素求和,计算和的最小值。注意:两对元素如果对应于array1和......
  • 华为OD机试真题---第k个排列
    针对华为OD机试真题中的“第k个排列”问题,以下是对题目的详细解析及解答方法:题目描述给定参数n,从1到n会有n个整数:1,2,3,…,n。这n个数字共有n!种排列。按大小顺序升序列出所有排列的情况,并一一标记。给定n和k,返回第k个排列。输入与输出输入:第一行为n,给定n的范围是......
  • 深入 MUX 的三态机制
    电路中一个输出连接多个输入,需要提高输出门的驱动能力;若多个输出连接一个输入,则需要引入高阻态保证逻辑的正确性。一般CMOS的逻辑门单元理想状态下同一时刻总有一个连通,是无法输出高阻态的。输入高阻态需要特殊的器件,在PDK中一般以传输门或者三态buf方式实现。MUX:逻辑实现......
  • Java类加载器
    书接上回。。3.类加载器Java虚拟机设计团队有意把类加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”(ClassLoader)。3.1类与类加载器......