• 代理模式


    1. 定义 为其他对象提供一种代理以控制对这个对象的访问。
    2. 本质 控制对象访问
    3. 实例 以歌星为例:歌星的合作过程 面谈,签合同,唱歌,收尾款 其实有些步骤不需要明星亲自去做 比如面谈,签合同,收尾款。明星只需要唱歌即可。其他交由经纪人去做!

    静态代理实现:

    Star 歌星

    /**
     * 歌星
     * @author lijun
     * @since 2018-03-12 14:12
     */
    public interface Star {
    
    
        /**
         * 面谈
         */
        void confer();
    
        /**
         * 签合同
         */
        void signContract();
    
        /**
         * 唱歌
         */
        void  sing();
    
        /**
         * 收尾款
         */
        void collectMoney();
    }

    JackyCheung 具体的歌星张学友

    /**
     * 张学友
     * @author lijun
     * @since 2018-03-12 14:14
     */
    public class JackyCheung implements Star {
        /**
         * 面谈
         */
        @Override
        public void confer() {
    
        }
    
        /**
         * 签合同
         */
        @Override
        public void signContract() {
    
        }
    
        /**
         * 唱歌
         */
        @Override
        public void sing() {
            System.out.println("张学友唱歌。。。。");
        }
    
        /**
         * 收尾款
         */
        @Override
        public void collectMoney() {
    
        }
    }

    经纪人

    /**
     * 经纪人
     * @author lijun
     * @since 2018-03-12 14:18
     */
    public class Agent implements Star{
    
    
        private Star star;
    
    
        public Agent(Star star) {
            this.star = star;
        }
    
        /**
         * 面谈
         */
        @Override
        public void confer() {
            System.out.println("经纪人代表面谈!");
        }
    
        /**
         * 签合同
         */
        @Override
        public void signContract() {
            System.out.println("经纪人代表签合同!");
        }
    
        /**
         * 唱歌
         */
        @Override
        public void sing() {
            star.sing();
        }
    
        /**
         * 收尾款
         */
        @Override
        public void collectMoney() {
            System.out.println("经纪人代表收尾款!");
        }
    }

    只有唱歌 需要具体的明星来做!其他都交由经纪人来做!

    调用:

     public void sing(){
            Star star = new JackyCheung();
            Agent agent = new Agent(star);
            agent.confer();
            agent.signContract();
            agent.sing();
            agent.collectMoney();
        }
    

    输出:

    经纪人代表面谈!
    经纪人代表签合同!
    张学友唱歌。。。。
    经纪人代表收尾款!

    用JDK动态代理实现

    /**
     * 动态代理的经纪人
     * @author lijun
     * @since 2018-03-12 14:57
     */
    public class AgentDynamic implements InvocationHandler{
        private Star star;
    
        /**  获取代理对象
         * @param target star
         * @return Object
         */
      public Object getInstance(Star target){
          this.star = target;
          Class<? extends Star> aClass = target.getClass();
          return Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),this);
      }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              Object object = null;
            String name = method.getName();
             if (name.equals("sing")){
                 System.out.println("经纪人代表面谈!");
                 System.out.println("经纪人代表签合同!");
                 object =  method.invoke(star, args);
                 System.out.println("经纪人代表收尾款!");
             }
            return object;
        }
    }

    调用:

     public void singDynamic(){
            AgentDynamic agentDynamic = new AgentDynamic();
            Star star  = (Star)agentDynamic.getInstance(new JackyCheung());
            System.out.println(star.getClass());
            star.sing();
        }

    输出:

    class com.sun.proxy.$Proxy4
    经纪人代表面谈!
    经纪人代表签合同!
    张学友唱歌。。。。
    经纪人代表收尾款!

    上面看到生成的代理类名字为$Proxy4 里面的类容是什么呢!我可以把类容写到磁盘!
    修改测试方法把类写到磁盘!

      public void singDynamic(){
            AgentDynamic agentDynamic = new AgentDynamic();
            Star star  = (Star)agentDynamic.getInstance(new JackyCheung());
            System.out.println(star.getClass());
            star.sing();
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy4", new Class[]{Star.class});
            try {
                FileOutputStream fileOutputStream = new FileOutputStream("E:\$Proxy4.class");
                fileOutputStream.write(bytes);
                fileOutputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }

    反编译 $Proxy4.class 得到:

    import com.junli.staticed.Star;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy4 extends Proxy implements Star {
        private static Method m1;
        private static Method m4;
        private static Method m6;
        private static Method m2;
        private static Method m3;
        private static Method m5;
        private static Method m0;
    
        public $Proxy4(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final void signContract() throws  {
            try {
                super.h.invoke(this, m4, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void collectMoney() throws  {
            try {
                super.h.invoke(this, m6, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void confer() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void sing() throws  {
            try {
                super.h.invoke(this, m5, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m4 = Class.forName("com.junli.staticed.Star").getMethod("signContract");
                m6 = Class.forName("com.junli.staticed.Star").getMethod("collectMoney");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.junli.staticed.Star").getMethod("confer");
                m5 = Class.forName("com.junli.staticed.Star").getMethod("sing");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }

    可以看出生成类的过程,可以看到JDK动态代理的原理:
    1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
    2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
    3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
    4、编译新生成的Java代码.class
    5、再重新加载到JVM中运行

    知道原理了我们就可以自己实现JDK动态代理的功能!其实关键就是Proxy代理类的实现!实现如下:

    自定义的动态代理实现

    LIInvocationHandler 自定义的InvocationHandler

    /**
     * 自定义的InvocationHandler
     * @author lijun
     * @since 2018-03-12 17:02
     */
    public interface LIInvocationHandler {
        /**
         *
         * @param proxy proxy
         * @param method method
         * @param args args
         * @return
         * @throws Throwable
         */
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable;
    }

    LIClassLoader 自定义类加载器

    /**
     *  
     * @author lijun
     * @since 2018-03-12 17:59
     */
    public class LIClassLoader extends ClassLoader{
    
        private File classPathFile;
    
        public LIClassLoader(){
            String classPath = LIClassLoader.class.getResource("").getPath();
            this.classPathFile = new File(classPath);
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            {
    
                String className = LIClassLoader.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();
                        }finally {
                            if(null != in){
                                try {
                                    in.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
    
                            if(out != null){
                                try {
                                    out.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
    
                }
    
                return null;
    
            }
        }
    
    }

    LIProxy 自定义的代理类

    /**
     * 自己的代理类
     * @author lijun
     * @since 2018-03-12 17:58
     */
    public class LIProxy {
    
        public static final String ln = "
    ";
    
        public static Object newProxyInstance(LIClassLoader classLoader, Class<?>[] interfaces, LIInvocationHandler h) {
            try {
                //1、动态生成源代码.java文件
                String src = generateSrc(interfaces);
                //2、Java文件输出磁盘
                String filePath = LIProxy.class.getResource("").getPath();
                System.out.println(filePath);
                File f = new File(filePath + "$Proxy4.java");
                FileWriter fw = new FileWriter(f);
                fw.write(src);
                fw.flush();
                fw.close();
    
                //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("$Proxy4");
                Constructor c = proxyClass.getConstructor(LIInvocationHandler.class);
                //f.delete();
    
                //5、返回字节码重组以后的新的代理对象
                return c.newInstance(h);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private static String generateSrc(Class<?>[] interfaces){
    
            StringBuffer sb = new StringBuffer();
            sb.append("package com.junli.custom;" + ln);
            sb.append("import com.junli.staticed.Star;" + ln);
            sb.append("import java.lang.reflect.Method;" + ln);
            sb.append("public class $Proxy4 implements " + interfaces[0].getName() + "{" + ln);
    
            sb.append("LIInvocationHandler h;" + ln);
    
            sb.append("public $Proxy4(LIInvocationHandler 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();
        }
    }

    AgentCustomDynamic 自定义 动态代理的经纪人

    /**
     *自定义 动态代理的经纪人
     * @author lijun
     * @since 2018-03-12 14:57
     */
    public class AgentCustomDynamic implements LIInvocationHandler{
        private Star star;
    
        /**  获取代理对象
         * @param target star
         * @return Object
         */
      public Object getInstance(Star target){
          this.star = target;
          Class<?> aClass = target.getClass();
          return LIProxy.newProxyInstance(new LIClassLoader(),aClass.getInterfaces(),this);
      }
    
        /**
         * 参数:
         *proxy 被代理的对象
         *method 被代理对象的方法
         *args 方法的参数
         * 返回:
         *Object 方法返回值
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object object = null;
            String name = method.getName();
             if (name.equals("sing")){
                 System.out.println("经纪人代表面谈!");
                 System.out.println("经纪人代表签合同!");
                 object =  method.invoke(star, args);
                 System.out.println("经纪人代表收尾款!");
             }
            return object;
        }
    }

    调用

    @Test
        public void singCustom() {
            AgentCustomDynamic agentCustomDynamic = new AgentCustomDynamic();
            Star star  = (Star)agentCustomDynamic.getInstance(new JackyCheung());
            System.out.println(star.getClass());
            star.sing();
        }
    

    输出

    class com.junli.custom.$Proxy4
    经纪人代表面谈!
    经纪人代表签合同!
    张学友唱歌。。。。
    经纪人代表收尾款!

    实现了动态代理的功能!

    Cglib 实现

    /**
     * Cglib动态代理实现
     * @author lijun
     * @since 2018-03-12 16:11
     */
    public class AgentCglib implements MethodInterceptor {
    
        /**
         *
         * @param clazz clazz 被代理类的具体实现类
         * @return Object
         */
        public Object getInstance(Class<?> clazz){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
           return enhancer.create();
        }
        /**
         * 拦截所有目标类方法的调用
         * 参数:
         * obj目标实例对象
         *method 目标方法的反射对象
         * args方法的参数
         * proxy代理类的实例
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            Object object = null;
    
            String name = method.getName();
            if (name.equals("sing")){
                System.out.println("经纪人代表面谈!");
                System.out.println("经纪人代表签合同!");
                object =  methodProxy.invokeSuper(o, objects);
                System.out.println("经纪人代表收尾款!");
            }
            return object;
        }
    }

    调用

        @Test
        public void singCglib() {
            AgentCglib agentCglib = new AgentCglib();
            Star star  = (Star)agentCglib.getInstance(JackyCheung.class);
            System.out.println(star.getClass());
            star.sing();
        }
         @Test
        public void singCglib() {
            AgentCglib agentCglib = new AgentCglib();
            Star star  = (Star)agentCglib.getInstance(JackyCheung.class);
            System.out.println(star.getClass());
            star.sing();
        }

    输出:

    class com.junli.staticed.JackyCheung$$EnhancerByCGLIB$$89c7b75a
    经纪人代表面谈!
    经纪人代表签合同!
    张学友唱歌。。。。
    经纪人代表收尾款!
    

    代理模式学习完毕!

    源码地址

  • 相关阅读:
    洛谷 P1850 换教室(期望dp)
    简单异或 && 洛谷 P1469 找筷子 && 洛谷 P3908 数列之异或
    2020 CSP-J复赛题解
    2018 ICPC 南京 D Country Meow(模拟退火|三分)
    佩尔方程
    块速幂/光速幂
    1436F
    反Nim游戏
    P1447 [NOI2010]能量采集(莫比乌斯反演)
    P3768 简单的数学题 (莫比乌斯反演+杜教筛)
  • 原文地址:https://www.cnblogs.com/mokingone/p/9109011.html
Copyright © 2020-2023  润新知