波神

导航

java常用设计模式八:代理模式

一、概述

代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 其特征是代理类与委托类有同样的接口,真正的核心业务逻辑还是在实际对象里面。

二、为什么要使用代理模式

  • 当客户端不想直接调用实际对象,或是客户端直接调用实际对象有困难。
  • 比如:想在实际对象的业务方法执行前或执行后额外处理一些事情。但是又不能修改原来的实际对象的方法,这时候也可以用代理模式。

三、代理模式的分类

 1、静态代理(在程序运行前,代理类的.class文件已经存在,所以称为静态代理)

1)原业务接口

public interface SourceObject {
    void operation();
}

2)原业务接口的实现类

public class SourceObjectImpl implements SourceObject {
    public void operation() {
        System.out.println("这是原业务核心方法");
    }
}

3)静态代理类

public class StaticProxy implements SourceObject {
    private SourceObjectImpl srcObj;
    public StaticProxy(SourceObjectImpl srcObj){
        this.srcObj = srcObj;
    }
    public void operation() {
        System.out.println("原业务方法执行前:记录处理中日志");
        srcObj.operation();
        System.out.println("原业务方法执行前:记录完成日志");
    }
}
public class StaticProxy implements SourceObject {
    private SourceObject srcObj;
    public StaticProxy(SourceObject srcObj){
        this.srcObj = srcObj;
    }
    public void operation() {
        System.out.println("原业务方法执行前:记录处理中日志");
        srcObj.operation();
        System.out.println("原业务方法执行前:记录完成日志");
    }
}

4)测试类

public class Client {
    public static void main(String[] args){
        SourceObject srcObj = new SourceObjectImpl();
        StaticProxy staticProxy = new StaticProxy(srcObj);
        staticProxy.operation();
    }
}
原业务方法执行前:记录处理中日志
这是原业务核心方法
原业务方法执行前:记录完成日志

由以上的结构可知:每个接口(SourceObject)有一个与之对应的代理类(StaticProxy),如果再有一个接口,那么就要同时新增一个代理类,这种情况在接口很多的时候,就会产生很多代理类。是否能只有一个代理类呢?当然是可以的,就是动态代理

 

 2、动态代理(在程序运行前,代理类的.class文件不存在,是运行时序由Java反射机制动态生成)

  动态代理主要是借助 类Proxy、接口InvocationHandler 来实现的。下面以一个具体的例子来说明 动态代理的过程

 

  1)原业务接口

public interface SourceObject {
    void operation();
}

2)原业务接口的实现类

public class SourceObjectImpl implements SourceObject {
    public void operation() {
        System.out.println("这是原业务核心方法");
    }
}

3)新建动态代理类处理器(注意,该类并不是SourceObject的代理类,它并没有实现于接口SourceObject,因此它不能调用operation()方法,这是与静态代理 最大的不同之处,代理类是程序运行的时候才动态产生的。)

public class DynamicProxyHandler implements InvocationHandler {
    private Object srcObj;//被代理的实际对象,定义为Object类型表明,可以是任意对象

    /**
     * 该方法负责动态创建代理类,并返回代理类的实例,这个实例的类继承于java.lang.reflect.Proxy,还实现了传入进来的srcObject的原业务接口。
     *
     * @param srcObj
     * @return
     */
    public Object getProxyInstance(Object srcObj) {
        this.srcObj = srcObj;
        return Proxy.newProxyInstance(srcObj.getClass().getClassLoader(), srcObj.getClass().getInterfaces(), this);
    }

    /**
     * 注意:客户端不会真正的显示调用该方法,当通过getProxyInstance取得的实例执行真正的方法时,该方法会执行。
     *
     * @param proxy  参数传递的是动态生成的代理类的实例,本方法并没有使用它
     * @param method 是调用的方法,即需要执行的方法
     * @param args   是执行方法的参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("原业务方法执行前:记录处理中日志");
        System.out.println("invoke 方法的第一个参数proxy 的类是:" + proxy.getClass().toString());
        method.invoke(srcObj, args);
        System.out.println("原业务方法执行前:记录完成日志");
        return null;
    }
}

4)测试类

public class Client {
    public static void main(String[] args){
        SourceObject srcObj = new SourceObjectImpl();
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        //为什么这里可以用SourceObject来接收getProxyInstance返回的实例呢?从后面的结果可知道动态产生的代理类实质上是继承于Proxy类,并实现于SourceObject
        SourceObject dynamicProxyInstance = (SourceObject)dynamicProxyHandler.getProxyInstance(srcObj);
        System.out.println("dynamicProxyInstance 的类是:================="+dynamicProxyInstance.getClass().toString());
        System.out.println("dynamicProxyInstance 的父类是:==============="+dynamicProxyInstance.getClass().getSuperclass());
        System.out.println("dynamicProxyInstance 实现的接口如下:===========");
        Class<?>[] interfaces=dynamicProxyInstance.getClass().getInterfaces();
        for(Class<?> i:interfaces){
            System.out.println(i.getName());
        }
        System.out.println("dynamicProxyInstance 的方法有:===============");
        Method[] method=dynamicProxyInstance.getClass().getDeclaredMethods();
        for(Method m:method){
            System.out.println(m.getName());
        }
        //执行真正的核心业务方法
        System.out.println("dynamicProxyInstance 执行原业务方法:===============");
        dynamicProxyInstance.operation();


        //以下的代码是将动态生成的代理类保存到target的classes里面,便于查看。
        byte[] bts = ProxyGenerator.generateProxyClass("$Proxy0", interfaces);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(new File("target/classes/proxy/demo/$Proxy0.class"));
            fos.write(bts);
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
dynamicProxyInstance 的类是:=================class com.sun.proxy.$Proxy0
dynamicProxyInstance 的父类是:===============class java.lang.reflect.Proxy
dynamicProxyInstance 实现的接口如下:===========
proxy.demo.SourceObject
dynamicProxyInstance 的方法有:===============
equals
toString
hashCode
operation
dynamicProxyInstance 执行原业务方法:===============
原业务方法执行前:记录处理中日志
invoke 方法的第一个参数proxy 的类是:class com.sun.proxy.$Proxy0
这是原业务核心方法
原业务方法执行前:记录完成日志

 

由以上结果可知:程序运行时动态生成了一个代理类com.sun.proxy.$Proxy0,它的父类是Proxy,并且还实现了接口SourceObject。这个代理类是由Proxy的 newProxyInstance 方法生成的。生成的代理类的源代码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.demo.SourceObject;

public final class $Proxy0 extends Proxy implements SourceObject {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void operation() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("proxy.demo.SourceObject").getMethod("operation");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

当调用  dynamicProxyInstance.operation() 的时候,实质上就是调用了以上生成的代理类中红色标注的方法。

   super.h.invoke(this, m3, (Object[])null);

super就是指父类Proxy,h就是指InvocationHandler的实例,这里应该是传入的子类DynamicProxyHandler 的实例,所以h.invoke方法,就是执行DynamicProxyHandler的invoke方法。

 

posted on 2019-01-10 18:16  波神  阅读(172)  评论(0编辑  收藏  举报