01-设计模式:JDK动态代理

2021-01-06  本文已影响0人  XAbo

代理模式:在不改变原有类的前提下,对原有类进行业务增强。
动态与静态代理区别:动态代理的代理类是被用的时候在内存中创建。
jdk方式代理类:必须实现的有接口。

问题:如何给Manager方法add()执行前后增加额外的日志逻辑呢?


package realclass;
import interfaces.ControlDB;
import interfaces.ControlUI;

public class Manager implements ControlDB{
   
    @Override
    public void add() {
        // TODO Auto-generated method stub
       System.out.println("我是Manager,数据添加中……");
    }
}

1、静态代理

package proxyclass;
import realclass.Manager;
import interfaces.ControlDB;
import interfaces.ControlUI;

public class ManagerLog_JT implements ControlDB  {

    private Manager manager ;
    public ManagerLog_JT(){
        manager=new Manager();
    }    
       @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("我是ManagerLog_JT,日志记录开始……");
        manager.add();
        System.out.println("我是ManagerLog_JT,日志记录结束……");
    }
}

2、聚合方式

package proxyclass;
import interfaces.ControlDB;

public class ManagerLog_JH implements ControlDB {

   ControlDB controlDB;
   public ManagerLog_JH(ControlDB controlDB){
       this.controlDB=controlDB;
   }
   @Override
   public void add() {
       // TODO Auto-generated method stub
       System.out.println("我是ManagerLog_JH,日志记录开始……");
       controlDB.add();
       System.out.println("我是ManagerLog_JH,日志记录结束……");
   }
}

3、测试类:

import interfaces.ControlDB;
import proxyclass.ManagerLog_JH;
import proxyclass.ManagerLog_JT;
import realclass.Manager;

public class ProxyTest {
    public static void main(String[] args) {
     // 正常调用Manager
      Manager manager= new Manager();
      manager.add();
      System.out.println("==============================分割线============================");
      System.out.println("为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:");
      System.out.println("————————————————————静态方式开始————————————————————");
      ControlDB  managerlog_jt=new ManagerLog_JT();
      managerlog_jt.add();
      System.out.println("————————————————————静态方式结束————————————————————");
      System.out.println("————————————————————聚合方式开始————————————————————");
      ControlDB managerlog_jh=new ManagerLog_JH(new Manager());
      managerlog_jh.add();
      System.out.println("————————————————————聚合方式结束————————————————————"); 
            
    }

}

4、结果

我是Manager,数据添加中……
==============================分割线============================
为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:
————————————————————静态方式开始————————————————————
我是ManagerLog_JT,日志记录开始……
我是Manager,数据添加中……
我是ManagerLog_JT,日志记录结束……
————————————————————静态方式结束————————————————————
————————————————————聚合方式开始————————————————————
我是ManagerLog_JH,日志记录开始……
我是Manager,数据添加中……
我是ManagerLog_JH,日志记录结束……
————————————————————聚合方式结束————————————————————

5、分析
不管哪种方式最终结果是代码的臃肿:

image.png

6、动态代理

原理:
1.在运行时根据反射生成一个被代理对象类似的“内存对象”。
2.“内存对象”可以执行原有对象的原生方法。
3.在执行原生方法前后可以增加业务逻辑。
4.增加的业务逻辑需用户自定义。

jdk实现的动态代理应用

package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import proxyclass.ManagerLog_Proxy;
import realclass.Manager;

public class ManagerInvocationHandler implements InvocationHandler {
        private Object obj; 
        public ManagerInvocationHandler(Object obj) {
            this.obj = obj;
        }
        
        public static  Object getProxyInstanceFactory(Object realObj){
        Class<?> classType = realObj.getClass(); 
       /* 参数1:被代理对象的类加载器,用来加载代理对象的字节码文件。
          参数2:被代理对象实现的接口,用来是代理对象与被代理对象保持方法一致。
          使用参数1、2保证了【原理1】
       */
        return Proxy.newProxyInstance(classType.getClassLoader(),classType.getInterfaces(), new ManagerInvocationHandler(realObj));
        }
    
    @Override
      //实现了【原理2 3 4】关键是该方法能被内存中的代理类调到
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {          
        System.out.println("before========日志生成");
        method.invoke(obj, args);       
        System.out.println("after=========日志结束");
        return null;
    }

}

动态代理的测试类:

package test;
import interfaces.ControlDB;
import interfaces.ControlUI;
import realclass.Manager;
import realclass.UserA;

public class ProxyTest {
    public static void main(String[] args) {
 
     System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
      //返回内存中的代理类(无逻辑的方法体)      
      Manager manager= new Manager(); 
      //拿到代理类,执行内存类中的方法
      ControlUI managerui= (ControlUI) ManagerInvocationHandler.getProxyInstanceFactory(manager);      
      managerui.change();    
   }
}

内存中的类$Proxy0:如何生成看后续JAVA反射专题,会模拟jdk生成动态类。


//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.temp.ControlDB;
import com.temp.ControlUI;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements ControlDB, ControlUI {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
         //继承父类就是为了使用父类的中的属性InvocationHandler
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void change() throws  {
        try {
           //回调invoke方法:super.h是因为父类才有InvocationHandler属性。
            super.h.invoke(this, m4, (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 add() throws  {
        try {
            super.h.invoke(this, m3, (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);
        } 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.temp.ControlUI").getMethod("change");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.temp.ControlDB").getMethod("add");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

代理类的父类:

public class Proxy implements Serializable {
    private static final long serialVersionUID = -2222568056686623797L;
    private static final Class<?>[] constructorParams = new Class[]{InvocationHandler.class};
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
    //I am here
    protected InvocationHandler h;
    private static final Object key0 = new Object();

    private Proxy() {
    }
  ……
}

其他动态代理的实现技术:cglib,javassist,asm。

上一篇下一篇

猜你喜欢

热点阅读