设计模式——动态代理

关键字:动态代理、代理模式、spring中的代理相关、装饰器模式

静态代理

首先建立一个接口interface,想要被代理的对象类A实现接口interface,想要使用的代理对象类B实现接口,并且在类中私有建立一个对象A,并且在B的构造函数里面初始化这个对象A(或者提供一个setter方法)。在接口实现的方法里可以编写要代理的逻辑并且调用对象A里面实现的方法。使用的时候先new一个对象A,然后将对象传给一个new对象B,调用B的方法,就实现了静态代理。

public interface Intervieew {
    public void mianshi();
}
public class Myintervieew implements Intervieew {
    @Override
    public void mianshi() {
        System.out.println("面试中-----");
    }
}

创建静态代理:

public class MyintervieewProxy implements Intervieew {
    private  Intervieew interView;
    public void setIntervieew(Intervieew  intervieew ) {
          this.interView = interView;
  }
    @Override
    public void mianshi() {
        System.out.println("请个大神过来帮我面试");
        interView.mianshi();
        
    }
}

动态代理:有proxy和cglib两种

首先建立一个接口interview和被代理的类与上面相似
和静态代理不同的是,代理逻辑对象实现invocationHandler接口
public class MyHandler implements InvocationHandler {
    private Object intverview ;
    public MyHandler(Object myintervieew){
        this.intverview = myintervieew;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res;
        System.out.println("请个大神来帮忙");
        res = method.invoke(intverview,args);
        System.out.println("面试结束,回家养猪");
        return res;
    }
}

其实到这里就可以使用了,但是我们为了代码的美感,进行封装一个代理工厂类。

封装成一个工厂类
public class ProxyFactory {
    public static Object getProxy(Object myintervieew){
        MyHandler handler = new  MyHandler(myintervieew);
        return Proxy.newProxyInstance(myintervieew.getClass().getClassLoader(),myintervieew.getClass().getInterfaces(),handler);
    }
}

动态代理的关键便是实现invocationHandler接口和使用Proxy.newProxyInstance方法(可以注意到这里是返回了一个全新的对象)。

下面是测试案例
public class Test {
    public static void main(String[] args) {
        Intervieew myintervieew = new Myintervieew();
        Intervieew proxy = (Intervieew) ProxyFactory.getProxy(myintervieew);
        proxy.mianshi();
    }
}
cglib包需要另行下载包,就没有记录。invocationHandler接口代理需要代理类实现一个接口,然后通过反射的方式。cglib则不需要接口,他是建立一个被代理类的子类来实现代理,所以cglib不能代理由final修饰的类
动态代理与静态代理的区别:

静态代理模式可以看到我们创建的代理对象是我们自己写好的,也就是MyintervieewProxy这个类,在运行时是会编译成一个class文件存在我们的项目中的。但是动态代理是没有编译成这个class文件存在的,MyHandler存放的只是我们需要代理的逻辑,但是最终创建的对象是Proxy.newProxyInstance返回的对象,这个对象是没有生成相应的class文件的,它是虚拟机在运行的时候生成字节码放在jvm中。这也就是所谓的动态与静态。

spring中的代理理解:

spring有一个叫容器的技术,就是可以存放bean对象,我们要用到这个对象时直接从容器中获取。加入有一个对象A存放在容器中,我们现在要获取A,但是A可能需要创建代理进行增强等。但是我们使用的时候并不需要知道A是否创建了代理,我们获取A后还是用A去接收。

public class Test implement BeanPostProcessor{
    private Map container;
    public static void main(String[] args) {
        putIntoContainer(new A, a);
      //存放对象到容器中,框架层处理的,一般对程序员不感知,程序员只知道容器中有a,但是存放的是不是a并不清楚,这里我们对a做了特殊处理放进去一个B(代理)
        Object B = getFromContainer(a);
        //这里我们用什么类型接收容器中获取到的a呢??
        //如果a实现了某种接口,比如Intervieew,那么我们可以这样接收
         //Intervieew B = getFromContainer(a);  这个就是文中动态代理的实现方式可以这样处理
        // 如果A没有实现接口呢,那怎么办?
       // A B = getFromContainer(a);如果B是A的子类不就可以这样接收了吗?
       //cglib包就是这样操作的。它会动态生成一个代理类B extends A
    }
    private void  putIntoContainer(Object bean, String key){
         if(bean instanceof A) {
             //创建代理对象B 
             container.put(key, B);
          }
    }

  private Object getFromContainer(String key) {
          return container.get(key);
    }
}

其实不仅是spring,一个框架都应该考虑这种情况的处理。

代理模式和装饰器模式

这两种模式都是对原有功能的增强,装饰器典型应用就是java的文件流处理。

        FileInputStream fileInputStream = new FileInputStream("");
        InputStreamReader reader = new InputStreamReader(fileInputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);

通过一层一层包装实现功能增强,如果关闭只需要关闭一个就好了

bufferedReader.close();
//底层的close代码
    public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
            try {
                in.close();
            } finally {
                in = null;
                cb = null;
            }
        }
    }

FileInputStream、InputStreamReader、BufferedReader这里这三个虽然功能不同,但本质上还是流,他们是有一定的内在联系的。但是代理模式因实现方式区别可能也会实现相同的接口,但是代理与被代理对象之间的联系我们不是很在意的,更加关注功能的不同。

你可能感兴趣的:(设计模式——动态代理)