zoukankan      html  css  js  c++  java
  • 设计模式五 代理模式

    0、基本定义

    为其他对象提供一种代理以控制对这个对象对访问。

    静态代理:代理前,所有对行为都是已知对。 不能扩展

    动态代理:代理前,所有的行为都是未知的。

    》 jdk:必须实现 interface,从interface中,获取method,进行字节码重组,生成新类。

    》 cgli:对类进行代理,Enhance 需要设置 被代理的类作为 superClass,生成被代理类的子类。

    1、代码实现(gupao学院的demo)

    1.1 静态代理

    public class Father {
    
        private Son person;
    
        //强依赖,不能扩展
        public Father(Son person) {
            this.person = person;
        }
    
        public void findLove() {
    
            System.out.println("开始五色");
            this.person.findLove();
            System.out.println("结束");
        }
    }
    
    public class Son {
    
        public void findLove() {
    
            System.out.println("找对象,大长腿");
        }
    
    }
    
    public class StaticProxyTest {
    
        public static void main(String[] args) {
    
            Son son = new Son();
    
            Father father = new Father(son);
    
            father.findLove();
        }
    }

    1.2  动态代理

    采用tom老师经典案例,meipo

    jdk代理

    public interface Person {
    
        void findLove();
        void job();
    }
    
    public class XieMu implements Person{
    
        @Override
        public void findLove() {
    
            System.out.println("gaofus");
            System.out.println("身高175");
            System.out.println("人好");
        }
    
        @Override
        public void job() {
            System.out.println("salary 》 15k");
        }
    }
    
    
    public class JDKMeipo implements InvocationHandler{
    
        private XieMu target;
    
        public Object getInstance(XieMu target) {
    
            this.target = target;
    
            //生成新类
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this);
    
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            System.out.println( "我是媒婆,已经拿到需求");
            System.out.println( "开始五色");
            method.invoke(this.target,args);
            return null;
        }
    }
    
    public class JDK58 implements InvocationHandler{
    
        private Person target;
    
        public Object getInstance(Person target) {
    
            this.target = target;
    
            //生成新类
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this);
    
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            System.out.println( "我是58,开始找工作 ");
            method.invoke(this.target,args);
            return null;
        }
    }
    
    public class JDKProxyTest {
    
    
        public static void main(String[] args) throws IOException {
    
    //        Person instance = (Person) new JDKMeipo().getInstance(new XieMu());
    //        instance.findLove();
    
            Person proxy = (Person) new JDK58().getInstance(new XieMu());
            proxy.job();
    
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
            FileOutputStream fos = new FileOutputStream("$Proxy.class");
    
            fos.write(bytes);
            fos.close();
    
        }
    }

    cgli 代理

    public class Zhangsan {
    
        public void findLove() {
            System.out.println("人美");
        }
    }
    
    public class CglibMeipo implements MethodInterceptor {
    
        public Object getInstance(Class clazz) {
    
            Enhancer enhancer = new Enhancer();
            //设置生成新类的父类
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
           //增强
            System.out.println( "我是媒婆,已经拿到需求");
            System.out.println( "开始五色");
            methodProxy.invokeSuper(o, objects);
            System.out.println("合适");
    
            return null;
        }
    }
    
    
    public class CglibTest {
    
        public static void main(String[] args) {
    
            Zhangsan instance = (Zhangsan) new CglibMeipo().getInstance(new Zhangsan().getClass());
    
            instance.findLove();
    
            System.out.println(instance.getClass());
        }
    }

    1.3 自定义代理

    GPClassLoader.java

    public class GPClassLoader extends ClassLoader{
    
        private File classPathFile;
    
        public GPClassLoader() {
            String classPath = GPClassLoader.class.getResource("").getPath();
            this.classPathFile = new File(classPath);
        }
    
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
    
            String className = GPClassLoader.class.getPackage().getName() + "." + name;
            if (classPathFile != null) {
                File classFile = new File(classPathFile, name.replaceAll("\.", "/") + ".class");
                if (classFile.exists()) {
                    FileInputStream fis = null;
                    ByteArrayOutputStream out = null;
                    try {
                        fis = new FileInputStream(classFile);
                        out = new ByteArrayOutputStream();
                        byte[] buff = new byte[1024];
                        int len;
                        while ((len = fis.read(buff)) != -1) {
                            out.write(buff, 0, len);
                        }
                        return defineClass(className, out.toByteArray(), 0, out.size());
                    } catch (Exception e) {
    
                    } finally {
                        if (fis != null) {
                            try {
                                fis.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (out != null) {
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            return super.findClass(name);
        }
    }

    GPProxy.java

    public class GPProxy {
    
        public static Object newProxyInstance(GPClassLoader classLoader
                , Class<?>[] interfaces, GPInvocationHandler handler ) throws Exception {
    
            // 1、动态生成源代码
            String src = generateSrc(interfaces);
            //2、java文件 输出到 磁盘
            String filePath = GPProxy.class.getResource("").getPath();
            System.out.println(filePath);
    
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
    
            //3、生成的java文件 编译成 .class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manage.getJavaFileObjects(f);
    
            JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
            task.call();
            manage.close();
    
            //4、编译生成的.class文件加载到jvm中
            Class proxyClass =  classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
            f.delete();
            //5、返回字节码重组后的新的代理对象
            return c.newInstance(handler);
        }
    
        public static final String ln = "
    ";
        private static String generateSrc(Class<?>[] interfaces) {
    
            StringBuffer sb = new StringBuffer();
            sb.append("package com.zzf.design.proxy.custom;" + ln);
            sb.append("import com.zzf.design.proxy.jdk.Person;" + ln);
            sb.append("import java.lang.reflect.Method;" + ln);
            sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
    
            sb.append("GPInvocationHandler h;" + ln);
    
            sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);
    
            sb.append("this.h = h;");
    
            sb.append("}" + ln);
    
    
            for (Method m : interfaces[0].getMethods()){
                sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
                sb.append("try{" + ln);
                sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod("" + m.getName() + "",new Class[]{});" + ln);
                sb.append("this.h.invoke(this,m,null);" + ln);
                sb.append("}catch(Throwable e){" + ln);
                sb.append("e.printStackTrace();" + ln);
                sb.append("}");
                sb.append("}");
            }
    
            sb.append("}" + ln);
    
            return sb.toString();
        }
    }

    InvocationHandler.java

    public interface GPInvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }

    借此机会熟悉了下 ClassLoader ,一些IO流使用。受益很多。在此纪录。

    代理过程中 主要就是 字节码重组,生成了一个新类 $Proxy.java 。在平时的调试过程中,是找不到该类的,运行时使用后,就立马删除了。


    字节码重组原理 //1、拿到被代理对象的引用,并获取它的所有接口,反射获取 //2、jdk proxy 类重新生成一个新的类,同时新的类要实现被代理类所有实现方法 //3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用 //4、编译新生成的java代码 .class //5、在重新加载到 jvm中运行

    2 使用场景

    spring AOP 是使用代理很好的一种实现。

    ==========================================

    想学着用语言来进行描述,但还达不到程度,这更像是一份代码笔记。

    =========================================

    参考资料:

    咕泡学院

  • 相关阅读:
    ubuntu下使用golang、qml与ubuntu sdk开发桌面应用 (简单示例)
    Go Revel 学习指南
    Go Revel
    Go Revel
    Go Revel
    Go Revel
    Go Revel
    Go Revel
    Go Revel
    Go Revel
  • 原文地址:https://www.cnblogs.com/idea-persistence/p/9537758.html
Copyright © 2011-2022 走看看