• 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 = "
    ";
        private static final String tab = "	";
        private static final String doubleTab = "		";
        private static final String threeTab = "			";
        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();
            }
        }
    }
  • 相关阅读:
    Advanced Developer's Blog
    图片文字识别
    Unit test resources
    SpringBoot-mvn插件
    flask中使用proto3
    QTA-qtaf自动化测试实践
    AttributeError: module 'virtualenv' has no attribute 'create_environment'
    qtaf dick 报错 NameError: name 'dict_values' is not defined
    24点python实现
    mysql在win下移植
  • 原文地址:https://www.cnblogs.com/code-star/p/10520385.html
Copyright © 2020-2023  润新知