Java 动态代理

首先写下查找的对动态代理的定义:

动态代理就是想办法,根据接口或目标对象,计算出代理类的字节码,然后再加载到JVM中使用。

我的理解:

动态代理旨在java运行时(涉及到的知识:编译时、运行时、构建时)动态加载目标类,在实现目标类方法的基础上,使用自己的方法(jdk用反射,cjlib则利用ASM机制继承目标类)将自己需要的增强代码插入其中,以达到不修改原代码,只新添自己的代码而增强原方法功能的目的,从查到的方法可以知道,增强的代理类已经不是目标类,是新的类,新的字节码,目标类未发生变动.

首先写下涉及到的类:

public interface Person {
    public void speak();
}

 

public class Joker{//是否继承接口根据动态代理实现方式不同而不同,jdk的需要,cjlib不需要
   // @Override
    public void speak() {
        System.out.println("JokerSpeaking");
    }
}

然后是调用增强后方法的代码

    public static void main(String []args) throws Exception {
        Joker j = (Joker)getProxy(new Joker());
        j.speak();

    }

 最后就是重头戏,两种动态代理的实现方法:

用jdk实现的动态代理:

    private static Object getJDKProxy(final Object target) throws Exception {
        Object proxy = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//获取类加载器
                target.getClass().getInterfaces(),//获取目标类所实现的接口,这也是jsk动态代理目标类需要实现接口的原因
                (proxy1, method, args) -> {
                    System.out.println(method.getName() + "proxyEnhance");
                    Object result = method.invoke(target, args);//调用原方法
                    System.out.println(method.getName() + "proxyEnhanceEnd");
                    return result;
                }
        );
        return proxy;
    }

 用cjlib实现的动态代理:

    private static Object getCjlibProxy(final Object target) throws Exception {
        Enhancer e = new Enhancer();
        e.setSuperclass(target.getClass());
        e.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("前");
            Object invoke = method.invoke(target, objects);
            System.out.println("后");
            return invoke;
        });
        return e.create();
    }

 以前几次学动态代理,其核心代码虽然不变,但是看上去的形式却千差万别,这次仔细观察后发现,仅以上涉及到的代码就可以实现增强目标方法的目的,以前看上去差很多问题是出在代理类上:无论是jdk的InvocationHandler还是cjlib的MethodInterceptor(jdk中因为lamda表达式的关系省略了InvocationHandler的出现)都是可以自己继承并进行增强的,最后只需将自己实现的类替换其父类的位置仍然可以实现功能.

以下是大佬的两种代理方式的对比说明,链接:https://www.cnblogs.com/whirly/p/10154887.html

JDK 动态代理:
    为了解决静态代理中,生成大量的代理类造成的冗余;
    JDK 动态代理只需要实现 InvocationHandler 接口,重写 invoke 方法便可以完成代理的实现,
    jdk的代理是利用反射生成代理类 Proxyxx.class 代理类字节码,并生成对象
    jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口
    优点:解决了静态代理中冗余的代理实现类问题。
    缺点:JDK 动态代理是基于接口设计实现的,如果没有接口,会抛异常。
CGLIB 代理:
    由于 JDK 动态代理限制了只能基于接口设计,而对于没有接口的情况,JDK方式解决不了;
    CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。
    实现方式实现 MethodInterceptor 接口,重写 intercept 方法,通过 Enhancer 类的回调方法来实现。
    但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
    同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
    优点:没有接口也能实现动态代理,而且采用字节码增强技术,性能也不错。
    缺点:技术实现相对难理解些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值