浅谈动态代理

什么是动态代理?


以下为个人理解:

  • 动态代理就是在程序运行的期间,动态地针对对象的方法进行增强操作。并且这个动作的执行者已经不是"this"对象了,而是我们创建的代理对象,这个代理对象就是类似中间人的角色,帮助我们为目标方法嵌入一些其他的逻辑进去。

jdk动态代理的原理


  • jdk自带的动态代理的工作原理是利用反射的newInstance,创建一个代理对象(proxy),获取到目标接口的方法,然后我们就可以在Invoke之前或之后做操作。它抽取出了一个invokeHandler,里面就有目标method。

  • 试想一下,当我们拥有了class对象,增强逻辑(invokeHandler),也就是增强的目标方法之后,我们自己利用反射(不利用Proxy)也可以很容易写出我们自己的动态代理。但是问题就在于,我们只有明确了目标类之后,通过自己编写Proxy类,实现目标接口,往里面塞invoktionHandler, 最后New出来这个实实在在的对象。而jdk提供的动态代理,却可以在并不知情的情况下,帮我们做这一系列的动作。

  • jdk生成代理类时,并没有经历源码阶段,编译阶段,而是直接到字节码阶段,它生成的代理类是看不到的,因为它直接就是字节码文件了。 它帮我们继承了Proxy类,并且还动态的帮助我们继承了目标接口。也就是说,它帮我们写代码了。里面用到的技术,是ASM技术,它可以直接生成我们想要的字节码。

  • jdk方法反射调用优化:

  • invoke() 利用反射进行本地调用,效率低下,它在调用了一定的次数(16)之后会生成实例化对象,变成正常调用。

InvocationHandler接口

publicinterfaceInvocationHandler {
​
    publicObjectinvoke(Objectproxy, Methodmethod, Object[] args)throwsThrowable;
        
}

源码

@CallerSensitive
publicstaticObjectnewProxyInstance(ClassLoaderloader,
                                      Class<?>[] interfaces,
                                      InvocationHandlerh)
    throwsIllegalArgumentException
{
    Objects.requireNonNull(h);
​
    finalClass<?>[] intfs=interfaces.clone();
    finalSecurityManagersm=System.getSecurityManager();
    if (sm!=null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
​
    /*
     * Look up or generate the designated proxy class.
     */
    Class<?>cl=getProxyClass0(loader, intfs);
​
    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm!=null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
​
        finalConstructor<?>cons=cl.getConstructor(constructorParams);
        finalInvocationHandlerih=h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(newPrivilegedAction<Void>() {
                publicVoidrun() {
                    cons.setAccessible(true);
                    returnnull;
                }
            });
        }
        returncons.newInstance(newObject[]{h});
    } catch (IllegalAccessException|InstantiationExceptione) {
        thrownewInternalError(e.toString(), e);
    } catch (InvocationTargetExceptione) {
        Throwablet=e.getCause();
        if (tinstanceofRuntimeException) {
            throw (RuntimeException) t;
        } else {
            thrownewInternalError(t.toString(), t);
        }
    } catch (NoSuchMethodExceptione) {
        thrownewInternalError(e.toString(), e);
    }
}

cglib动态代理的原理


  • cglib动态代理的原理跟jdk的类似,只不过它是基于父类继承,也就是不需要实现接口就可以做增强。它的内部并不是InvoktionHandler,而是方法拦截器 MethodInterceptor 。

  • 前面的jdk动态代理,它是利用ASM技术帮我们动态编写了一个proxy对象,其中继承了Proxy父类,实现了目标接口,而cglib则是利用ASM直接帮助我们继承了目标类,不需要接口。

  • 并且有所区别的是,它不仅仅通过反射拿到method,还拿到了MethodProxy。

  • MethodInterceptor接口 继承了Callback接口,它的拦截方法里面有一个特殊的参数 MethodProxy,这玩意可以不通过反射调用方法,通过invokeSuper() 方法可以直接正常调用。

  • MethodProxy是怎么做到正常调用的?

  • 其实就是我们前面提到的,继承了Proxy父类之后,就得到了父类的原始方法,当我调用invokeSuper的时候,直接调用的就是父类的原始方法。

MethodInterceptor

publicinterfaceMethodInterceptorextendsCallback {
    Objectintercept(Objectvar1, Methodvar2, Object[] var3, MethodProxyvar4) throwsThrowable;
}

MethodProxy

  • invoke() 无反射调用

  • invokeSuper() 无反射调用

publicObjectinvoke(Objectobj, Object[] args) throwsThrowable {
    try {
        this.init();
        MethodProxy.FastClassInfofci=this.fastClassInfo;
        returnfci.f1.invoke(fci.i1, obj, args);
    } catch (InvocationTargetExceptionvar4) {
        throwvar4.getTargetException();
    } catch (IllegalArgumentExceptionvar5) {
        if (this.fastClassInfo.i1<0) {
            thrownewIllegalArgumentException("Protected method: "+this.sig1);
        } else {
            throwvar5;
        }
    }
}
publicObjectinvokeSuper(Objectobj, Object[] args) throwsThrowable {
    try {
        this.init();
        MethodProxy.FastClassInfofci=this.fastClassInfo;
        returnfci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetExceptionvar4) {
        throwvar4.getTargetException();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值