Java 反射与代理模式(静态代理模式/动态代理模式)

基础代理设计模式

代理设计模式的核心本质在于:一个接口有两个子类,一个负责真实业务,一个负责与真实业务有关的所有辅助性操作。按照这样的原则,一个基础的代理设计模式如下:

package test;
import java.lang.reflect.Constructor;

interface ISubject {    //核心操作接口
    void eat();         //吃饭是核心业务
}
//核心业务类
class RealSubject implements ISubject { //核心业务
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("饿了吃饭");
    }
}
//辅助业务类
class ProxySubject implements ISubject {
    private ISubject iSubject;
    public ProxySubject(ISubject iSubject) {
        this.iSubject = iSubject;
    }
    public void prevPare() {
        System.out.println("饭前准备");
    }
    public void afterEat() {
        System.out.println("饭后洗碗");
    }

    @Override
    public void eat() {
        this.prevPare();        //辅助业务 饭前的准备
        this.iSubject.eat();    //核心业务 吃饭
        this.afterEat();        //辅助业务 饭后洗碗
    }
}
//工厂类
class Factory {
    private Factory() {}
    public static <T> T getInstance(String className) {
        T t = null;
        try {
            t = (T) Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t;
    }
    public static <T> T getInstance(String className, Object obj) {
        T t = null;
        try {
            Constructor<?> con = 
                    Class.forName(className).getConstructor(obj.getClass().getInterfaces()[0]);
            try {
                t = (T) con.newInstance(obj);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t;
    }
}

public class Test {
    public static void main(String[] args) {
        ISubject iSubject = Factory.getInstance("test.ProxySubject", Factory.getInstance("test.RealSubject"));
        iSubject.eat();
    }
}

运行结果
这里写图片描述

以上程序如果结合反射之后,整体的处理会非常繁琐。不光开发端,使用者使用起来也很麻烦。对于以上操作,客户端最多只需要关系代理是谁,实际业务是谁即可。
例:修改工厂类与测试类

class Factory {
    private Factory() {}
    public static <T> T getInstance(String realClassName) {
        T t = null;
        try {
            t = (T) Class.forName(realClassName).newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t;
    }
    public static <T> T getInstance (String proxyClassName, String realClassName) {
        T t = null;
        T realObj = getInstance(realClassName);
        try {
            Constructor<?> con = Class.forName(proxyClassName).getConstructor(realObj.getClass().getInterfaces()[0]);
            try {
                t = (T) con.newInstance(realObj);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t;
    }
}

public class Test {
    public static void main(String[] args) {
        ISubject iSubject = Factory.getInstance("test.ProxySubject", "test.RealSubject");
        iSubject.eat();
    }
}

运行结果
这里写图片描述
修改后的运行结果和前面的一样,而且还简化了用户的使用。

基础代理设计
这里写图片描述

现在的问题是:在开发中并不知道项目会有多少个接口,如果这些接口都需要使用到代理模式,那么就意味着每一个接口都需要编写两个子类,再假设这些接口的代理类的功能几乎都一样。

之前的这种代理设计只是一种最简单的代理设计,所以这种代理设计只能够代理一个接口的子类对象,无法代理更多的接口子类对象。要想真正使用代理设计模式,我们需要引入动态代理设计模式。

动态代理设计模式

动态代理模式的核心特点:一个代理类可以代理所有需要被代理的接口的子类对象
动态代理模式设计
这里写图片描述

要想进行动态代理设计的实现,代理类不再具体实现于某一个接口。

/**
* 动态代理实现的标识接口,只有实现此接口才具备有动态代理的功能
*/
public interface InvocationHandler {
    /**
    * invoke表示的是调用执行的方法,但是所有的代理类返回给用户的接口对象都属于代理对象
    * 当用户执行接口方法的时候所调用的实例化对象就是该代理主题动态创建的一个接口对象
    * @param proxy 表示被代理的对象信息
    * @param method 返回的是被调用的方法对象,取得了Method对象则意味着可以使用invoke()反射调用方法
    * @param args 方法中接收的参数
    * @return 方法的返回值
    * @throws Throwable 可能产生的异常
    */
    public Object invoke(Object proxy, Method method, Object[] args){
        throws Throwable;
    }
}

如果要想进行对象的绑定,那么就需要使用一个Proxy程序类,这个程序类的功能是可以绑定所有需要绑定的接口子类对象,而且这些对象都是根据接口自动创建的,该类有一个动态创建绑定对象的方法:

public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException

例:动态代理设计实现

//动态代理模式的设计实现
interface ISubject {
    void eat (String msg, int num);
}

class RealSubject implements ISubject {
    @Override
    public void eat(String msg, int num) {
        System.out.println("我要吃" + num + "分量的 " + msg);
    }
}

//动态代理类
class ProxySubject implements InvocationHandler {
    //绑定任意接口的对象,使用Object描述
    private Object target;
    //实现真实对象的绑定处理,同时返回代理对象(这个对象是根据接口定义动态创建生成的代理对象)
    public Object bind(Object target) {
        //保存真实主题对象
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(), this);
    }
    public void prevHandle() {
        System.out.println("[ProxySubject]方法处理前");
    }
    public void afterHandle() {
        System.out.println("[ProxySubect]方法处理后");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.prevHandle();
        //反射调用方法
        Object ret = method.invoke(this.target, args);
        this.afterHandle();
        return ret;
    }
}

public class Test {
    public static void main(String[] args) {
        ISubject iSubject = (ISubject) new ProxySubject().bind(new RealSubject());
        iSubject.eat("宫保鸡丁", 20);
    }
}

运行结果
这里写图片描述

cglib实现动态代理

动态代理实现完成了,但是所有的代理设计模式都会存在一个问题:离不开接口。

如果现在有新的需求:实现没有接口的动态代理模式。Proxy类提供的创建动态代理对象的方法:

public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException

此时如果要想实现这样的要求,就必须依靠另外的第三方组件包:cglib。这个开发包才能帮用户实现这类的要求。

例:实现基于类操作的动态代理模式

package test ;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class Message {
    public void send() {
        System.out.println("www.bit.java.reflact") ;
    }
}
class ClassProxy implements MethodInterceptor { // 定义一个拦截器
    private Object target ; // 真实主题对象
    public ClassProxy(Object target) {
        this.target = target;
    }
    public void preHandle() {
        System.out.println("[ProxySubject] 方法处理前") ;
    }
    public void afterHandle(){
        System.out.println("[ProxySubject] 方法处理后") ;
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {
        this.preHandle() ;
        Object ret = method.invoke(this.target,objects) ;
        this.afterHandle() ;
        return ret ;
    }
}
public class TestClassProxy {
    public static void main(String[] args) {
        Message msg = new Message() ;
        // 负责代理关系的代理处理类
        Enhancer enhancer = new Enhancer() ;
        enhancer.setSuperclass(msg.getClass()) ;
        // 代理对象,以上就动态配置好了类之间的代理关系
        enhancer.setCallback(new ClassProxy(msg)) ;
        Message temp = (Message) enhancer.create() ;
        temp.send() ;
    }
}

猜你喜欢

转载自blog.csdn.net/Guijun6/article/details/80369514