Java设计模式之代理模式

现以一个小姑娘寻找对象的例子来说明java中静态代理,JDK动态代理和CGLIB动态代理的使用和原理。

假设存在两种角色,小姑娘和媒婆。其中小姑娘需要寻找对象,她会将需求告诉媒婆,媒婆作为中介,会帮助小姑娘寻找对象。下面以java代码来说明这个过程。

以下是java静态代理的实现过程:

 

public interface Person {
    int findLove();
}

 

public class Girl implements Person {

    @Override
    public int findLove() {
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("有6块腹肌");
        return 0;
    }
}
public class MeiPo implements Person {

    private Girl target;

    public MeiPo(Girl target){
        this.target = target;
    }

    @Override
    public int findLove() {
        before();
        this.target.findLove();
        after();
        return 0;
    }

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}
public class App {

    public static void main(String[] args) {
        Girl girl = new Girl();
        MeiPo meiPo = new MeiPo(girl);
        meiPo.findLove();
    }
}

以下是jdk动态代理的实现过程:

public interface IPerson {
    int findLove();
}
public class Girl implements IPerson{

    @Override
    public int findLove() {
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("有6块腹肌");
        return 0;
    }
}
public class MeiPo implements InvocationHandler {

    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
        before();
        Object obj = method.invoke(this.target, args);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}
public class App {

    public static void main(String[] args) {
        IPerson p = (IPerson)new MeiPo().getInstance(new Girl());
        p.findLove();
    }
}

以下是模拟jdk代理类而自定义实现的代理

/**
 * @Author long
 * @Date 2019/3/14 7:45
 * 自定义类加载器
 */
public class SelfClassLoader extends ClassLoader{
    // 文件的路径
    private File classPathFile;

    public SelfClassLoader(){
        String classPath = SelfClassLoader.class.getResource("").getPath();
        // 定义classPath为当前classPath
        System.out.println("classPath=" + classPath);
        this.classPathFile = new File(classPath);
    }

    // 重写查找类的方法,需传入类名
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //获取类的完全限定名
        String className = SelfClassLoader.class.getPackage().getName() + "." + name;
        //不为空的情况下,创建一个指向所指定类的文件
        if(classPathFile  != null){
            // 定位到具体的类下面
            File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
            // 如果该类已经存在,将该类加载到流中
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    // 该步骤将类加载到内存中
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
/**
 * @Author long
 * @Date 2019/3/13 7:52
 * SelfInvocationHandler,类似jdk的InvocationHandler
 */
public interface SelfInvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
/**
 * @Author long
 * @Date 2019/3/13 7:50
 * 自定义代理类,类似jdk代理类Proxy
 */
public class SelfProxy {
    // 定义的一些常量
    private static final String ln = "\n";
    private static final String tab = "\t";
    private static final String doubleTab = "\t\t";
    private static final String threeTab = "\t\t\t";
    private static final String dynamicClassName = "$Proxy0";

    /**
     *  该方法用于创建代理类,需要三个参数,类加载器ClassLoader,接口Interfaces,SelfInvocationHandler
     */
    public static Object newProxyInstance(SelfClassLoader classLoader, Class<?>[] interfaces, SelfInvocationHandler handler) {
        //1.动态生成源代码.java文件
        String src = generateSrc(interfaces);
        System.out.println(src);
        //2.将java文件输出到磁盘
        String filePath = SelfProxy.class.getResource("").getPath();
        File file = new File(filePath + dynamicClassName + ".java");
        FileWriter fw = null;
        try {
            fw = new FileWriter(file);
            fw.write(src);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fw.flush();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //3.编译成class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manager = compiler.getStandardFileManager(null, null , null);
        Iterable iterable = manager.getJavaFileObjects(file);
        JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);
        task.call();
        try {
            manager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //4.编译生成的class文件加载到jvm中
        Class proxyClass = null;
        try {
            proxyClass = classLoader.findClass(dynamicClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Constructor c = null;
        try {
            c = proxyClass.getConstructor(SelfInvocationHandler.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        file.delete();
        //5.返回字节码重组以后的代理对象
        Object result = null;
        try {
            result = c.newInstance(handler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //生成动态代理类的流
    private static String generateSrc(Class<?>[] interfaces) {
        StringBuffer buffer = new StringBuffer();
        // 定义类的包路径
        buffer.append("package gp.study.design.pattern.proxy.self;" + ln);
        // 引入需要用到的包
        buffer.append("import java.lang.reflect.*;" + ln);
        buffer.append("import gp.study.design.pattern.proxy.house.RentAction;" + ln);
        // 定义代理类,实现给定的接口(传入的是接口数组,该出暂时默认实现一个第一个接口)
        buffer.append("public class " + dynamicClassName + " implements " + interfaces[0].getName() + "{" + ln);

            // 代理类中持有SelfInvocationHandler的引用
            buffer.append(tab + "SelfInvocationHandler h;" + ln);

            // 创建代理类的构造方法,需要接受一个SelfInvocationHandler类型的参数
            buffer.append(tab + "public "+dynamicClassName + " (SelfInvocationHandler h){" + ln);
                buffer.append(doubleTab + "this.h = h;" + ln);
            buffer.append(tab + "}" + ln);

            // 该处只实现第一个接口的所有方法
            Method[] methods = interfaces[0].getMethods();
            for (Method m : methods) {
                // getParameterTypes方法返回一个class对象数组,以声明顺序表示此Method对象表示的形式参数类型。如果没有参数,返回长度为0的数组。
                Class<?>[] params= m.getParameterTypes();
                // 该字符串用以拼接方法的参数名称
                StringBuffer paramNames = new StringBuffer();
                // 该字符串用以拼接方法的参数值
                StringBuffer paramValues = new StringBuffer();
                // 该字符串用以拼接方法的类型
                StringBuffer paramClass = new StringBuffer();
                // 遍历这些paramTypes,获取需要的值
                for (int j = 0; j < params.length; j++) {
                    Class clazz = params[j];
                    String type = clazz.getName();
                    String paramName = toLowerFirstCase(clazz.getSimpleName());
                    // 参数类型 + 参数名(默认类型小写)
                    paramNames.append(type + " " + paramName);
                    // 参数值(类型转小写的值)
                    paramValues.append(paramName);
                    // 参数的class
                    paramClass.append(clazz.getName() + ".class");
                    // 如果有多个参数,需要用逗号分隔开
                    if (j < params.length -1) {
                        paramNames.append(",");
                        paramClass.append(",");
                        paramValues.append(",");
                    }
                }
                // 开始创建接口中的方法
                buffer.append(tab + "public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + "){" + ln);
                    buffer.append(doubleTab + "try{" + ln);
                        // 获取到接口的某个方法,通过调用类的getMethod方法
                        buffer.append(threeTab + "Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName()+ "\",new Class[]{"+ paramClass.toString() + "});" + ln);
                        //代用SelfInvocationHandler的invoke方法,传入的参数为当前动态代理对象this,获取到的方法m,以及参数值
                        buffer.append(threeTab + (hasReturn(m.getReturnType()) ? "return " : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})",m.getReturnType()) + ";" + ln);
                    // 捕获相关的异常
                    buffer.append(doubleTab + "}catch(Error _ex){ }"+ ln);
                    buffer.append(doubleTab + "catch(Throwable e){" + ln);
                        buffer.append(threeTab + "throw new UndeclaredThrowableException(e);" + ln);
                    buffer.append(doubleTab + "}"+ln);
                    buffer.append(doubleTab + getReturnEmptyCode(m.getReturnType()) + ln);
                buffer.append(tab + "}" + ln);
            }

        buffer.append("}" + ln);
        return buffer.toString();
    }


    private static Map<Class, Class> mapping = new HashMap<Class, Class>();
    static {
        mapping.put(int.class, Integer.class);
    }

    private static String getReturnEmptyCode(Class<?> returnClass){
        if(mapping.containsKey(returnClass)){
            return "return 0;";
        }else if(returnClass == Void.class){
            return "";
        }else {
            return "return null;";
        }
    }

    private static String getCaseCode(String code,Class<?> returnClass){
        if(mapping.containsKey(returnClass)){
            return "((" + mapping.get(returnClass).getName() +  ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

    // 判断是否有返回值
    private static boolean hasReturn(Class<?> clazz) {
        return clazz != Void.class;
    }

    // 将某个字符串的首字母转小写
    private static String toLowerFirstCase(String src) {
        char[] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }
}
public interface Person {
    int findLove();
}
/**
 * @Author long
 * @Date 2019/3/14 22:22
 */
public class Girl implements Person {
    @Override
    public int findLove() {
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("有6块腹肌");
        return 0;
    }
}
/**
 * @Author long
 * @Date 2019/3/14 22:16
 */
public class MeiPo implements SelfInvocationHandler {

    private Object target;

    public Object getInstance(Object target) throws Exception{
        this.target = target;
        // 此处传入target的信息,是要实现target接口定义的方法,传入SelfInvocationHandler是为了调用invoke方法
        return SelfProxy.newProxyInstance(new SelfClassLoader(), target.getClass().getInterfaces(), this);
    }

    // 该方法由动态代理类来调用,因为动态代理类持有该对象的引用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        before();
        Object obj = method.invoke(this.target, args);
        after();
        return obj;
    }


    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}
/**
 * @Author long
 * @Date 2019/3/14 22:23
 */
public class App {
    public static void main(String[] args) {
        try {
            Person obj = (Person) new MeiPo().getInstance(new Girl());
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

posted @ 2019-03-14 23:03  kafebabe  阅读(187)  评论(0编辑  收藏  举报