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 是使用代理很好的一种实现。

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

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

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

    参考资料:

    咕泡学院

  • 相关阅读:
    Realtime crowdsourcing
    maven 常用插件汇总
    fctix
    sencha extjs4 command tools sdk
    首次吃了一颗带奶糖味的消炎药,不知道管用不
    spring mvc3 example
    ubuntu ati driver DO NOT INSTALL recommand driver
    yet another js editor on windows support extjs
    how to use springsource tools suite maven3 on command
    ocr service
  • 原文地址:https://www.cnblogs.com/idea-persistence/p/9537758.html
Copyright © 2011-2022 走看看