Java基础之动态代理

132 阅读4分钟

回顾

在上两篇Java基础之反射机制Java基础之反射机制(续)介绍了java中反射机制的原理,其本质就是获取运行时类,通过类获取运行时类完整的结构并调用其属性方法等等。那么这个反射机制具体有什么作用或者说实际的应用呢?

动态代理的概念

动态代理时指客户通过代理类来调用其他对象的方法,并且时在程序运行时根据需要动态创建目标类的代理对象

说到动态代理,先了解下静态代理,"代理"故名思议就是当需要完成某项人物时,本身不去执行具体点操作,而是委托一个代理对象去完成该任务,设计模式-代理模式的“代理”便是该“代理”。

1.静态代理的实现

public interface ClothFactory {//功能接口
   void product();
}
public class NikeFactory implements ClothFactory{//被代理类
   @Override
   public void product() {
       System.out.println("nike 工厂开始生产");
   }
}

public class ProxyFactory implements ClothFactory {//代理类
   ClothFactory cf;

   public ProxyFactory(ClothFactory cf) {
       this.cf = cf;
   }

   @Override
   public void product() {
       System.out.println("proxy start");
       cf.product();
   }
}

ClothFactory cf=new NikeFactory();//调用
ProxyFactory pf=new ProxyFactory(cf);
pf.product();

我们通过上述代码可得知,静态代理就是构建一个代理对象来实现被代理对象上的方法,调用代理对象的方法继而就调用了被代理对象的方法,继而实现了“代理”;

我们若要委托代理类对象去操作被代理类对象,就必须使被代理类并去现对应的接口,这里的Nikefactroy就对应一个ProxyFactory,那以后若想代理Person就必须构建ProxyPerson来实现Person方法,这样是不是效率有点低?我们想能不能我给你个被代理类 和接口,那你自动给我构建个被代理对象并自动实现接口方法。

注意这个自动实现非常具有意义

2.动态代理的实现


interface Subject{//接口方法
    void  action();
}

class RealSubject implements  Subject{//被代理类
    @Override
    public void action() {
        System.out.println("被代理类开始执行");
    }
}

class MyInvocationHandler implements InvocationHandler{
    Object obj;//实现了接口的被代理类的声明

    public Object blind(Object obj){// 给被代理类对象实例化 和返回一个代理类的对象
        this.obj=obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始触发");
       Object returnVal= method.invoke(obj,args);
        return returnVal;
    }
}

RealSubject rs=new RealSubject();//构建代理对象
MyInvocationHandler mi=new MyInvocationHandler();
Subject sj= (Subject) mi.blind(rs);//构建被代理对象
sj.action();//触发

分析

对以上代码进行分析

其中MyInvocationHandler的blind方法传入了一个被代理类对象, 而Proxy.newProxyInstance()方法构建了一个代理类对象,该方法的三个参数

  • 类加载器 obj.getClass().getClassLoader() 即和被代理类同样的类加载器
  • obj.getClass().getInterfaces() 被代理类中的接口
  • this 当前的对象 为了后续invoke(触发)做准备

通过上面得知 我们给MyInvocationHandler传入了一个被代理类的对象后,其创建了被代理对象放在了成员变量中,而且返回了一个代理对象,Subject sj= (Subject) mi.blind(rs);然后我们调用代理类的对应方法自动调用了代理类的方法。这其中的自动是什么奥秘呢?

我们知道我们构建被代理对象时传入类加载器和接口方法和this,调用目标方法就转化成this invoke方法的调用。那么我需要在invoke方法中实现对被代理类相关方法的调用

 Object returnVal= method.invoke(obj,args);//触发被代理类对应方法
 return returnVal;//被代理类方法调用的返回值

这其中的黑魔法主要集中在MyInvocationHandler里我们需要做两件事

  • 我们告诉他我们需要的被代理类 和对应接口分别是什么?
  • 实现invoke 即完成代理类对被代理类的调用

那么其便会帮我们构建一个被代理对象,当触发方法时便调用invoke

总结

动态代理的实现稍微有点复杂,与静态相同的是我们都需要一个代理类来实现被代理的方法,不同的是动态代理加了一个黑盒子,你告诉他被代理类对象和目标接口,然后就给你一个代理类对象,你调用代理类对象,它就帮你触发invoke。有了这个黑盒子,我们就能在invoke中额外添加些打印的功能而不需要修改被代理类,这其实就是AOP编程的原理。

喜欢本文的朋友们,欢迎长按下图关注订阅号"我的编程笔记",收看更多精彩内容~~