动态代理设计模式

动态代理设计模式——我的理解

动态代理是指在运行时,动态生成代理类。即,代理类的字节码将在运行时生成并载入当前的ClassLoader。


JDK的动态代理

我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器(实现 InvocationHandler 接口,通过统一的invoke方法,对原函数的进行处理)就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。

java动态代理机制中有两个重要的类和接口InvocationHandler(接口)Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心

InvocationHandler接口

  • 每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用

Proxy类

  • Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法
注意:Jdk的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用jdk代理
  • Jdk的动态代理模式
  1. 获取被代理的对象的所有接口列表
  2. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
  3. 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
  4. 将对应的字节码转换为对于的class对象;
  5. 创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
  6. Proxy的class对象以创建的handler对象为参数,实例化一个proxy对象;
  • 实例源码
  1. 动态代理类
// 1.  生成 动态代理对象
// 2.  指定 代理对象运行目标对象方法时需要完成的 具体任务
// 注:需实现InvocationHandler接口 = 调用处理器 接口
// 所以称为 调用处理器类
public class DynamicProxy implements InvocationHandler {

    // 声明被代理的对象
    // 作用:绑定关系,即关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke()
    private Object ProxyObject;

    /**
    * 根据被代理对象,生成代理对象Proxy
    */ 
    public Object newProxyInstance(Object ProxyObject){

        // 被代理的对象
        this.ProxyObject = ProxyObject;

        // Proxy类 = 动态代理类的主类 
        // Proxy.newProxyInstance()作用:根据指定的类装载器、一组接口 & 调用处理器 生成动态代理类实例,并最终返回
        // 参数说明:
        // ClassLoader loader:指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
        // Class<?>[] interfaces:指定目标对象的实现接口,即要给目标对象提供一组什么接口。若提供了一组接口给它,那么该代理对象就默认实现了该接口,这样就能调用这组接口中的方法
        // InvocationHandler:指定InvocationHandler对象。即动态代理对象在调用方法时,会关联到哪个InvocationHandler对象
        return Proxy.newProxyInstance(ProxyObject.getClass().getClassLoader(),ProxyObject.getClass().getInterfaces(),this);

    }

    // 复写InvocationHandler接口的invoke()
    // 动态代理对象调用目标对象的任何方法前,都会调用调用处理器类的invoke()
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 参数说明:
        // Object proxy:动态代理对象(即哪个动态代理对象调用了method()
        // Method method:目标对象被调用的方法
        // Object[] args:指定被调用方法的参数
        Object result = null;
        // 通过Java反射机制调用目标对象方法,得到返回值
        result = method.invoke(ProxyObject, args);
        // 返回结果
        return result;
    }

}

CGLIB的动态代理

CGLIB是针对类来实现的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

  • CGLIB创建某个类A的动态代理类的模式
  1. 查找A上的所有非final的public类型的方法定义
  2. 将这些方法的定义转换成字节码
  3. 将组成的字节码转换成相应的代理的class对象
  4. 实现MethodInterceptor接口,用来处理对代理类上所有方法的请求(这个接口和Jdk动态代理InvocationHandler的功能和角色是一样的)
  • 实例和源码
  1. 被代理对象RealSubject
public class RealSubjectCglib{
    // 操作
    public String operate(){
        return "RealSubjectCglib";
    }
}
  1. 代理类
public class CglibProxy implements MethodInterceptor{

    // 被代理对象
    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        //Cglib中的加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        //设置要创建动态代理的类
        enhancer.setSuperclass(this.target.getClass());
        //设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实现intercept()方法进行拦截
        enhancer.setCallback(this);
        Object obj = enhancer.create();
        return obj;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable{

        Object object = proxy.invokeSuper(obj, args);
        return object;
    }
}
  1. 测试
public Test{
    public static void main(String[] args){
        // 创建代理对象
        CglibProxy proxy = new CglibProxy();
        RealSubjectCglib cglib = (RealSubjectCglib)proxy.getInstance(new RealSubjectCglib());
        // 代理操作
        cglib.operate();
    }
}
  • 注意:
    CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

如果觉得不错,来关注吧

tYkNnK.jpg

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值