动态代理

      动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。

委托接口

public interface DSubject {
    
    public String invokeMethod(String argument);

}
委托接口实现类

public class DRealSubject implements DSubject{

    @Override
    public String invokeMethod(String argument) {
        int i = 0;
        for(int j = 0; j < 100000000; j++){
            i++;
        }
        return "success";
    }

}
动态代理类

public class DSubjectInvocationHandler implements java.lang.reflect.InvocationHandler{
    
    private Object delegate;
    
    public DSubjectInvocationHandler(Object delegate) {
        this.delegate = Objects.requireNonNull(delegate, "delegate must not be null.");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        
        Object returnObject = method.invoke(delegate, args);
        
        long finish = System.currentTimeMillis();
        
              String strString =
        String.format("Object:%s,method:%s,argument:%s,cost(ms):%d,result:%s", 
                delegate.getClass().getSimpleName(), method.getName(), Arrays.toString(args), finish - start, returnObject);
        
        System.out.println(strString);
              return returnObject;
    }

}
测试

public class ProxyTest {
	
	public static void main(String[] args){
		DSubject delegate = new DRealSubject();
        java.lang.reflect.InvocationHandler invocationHandler = new DSubjectInvocationHandler(delegate);
        DSubject proxy = (DSubject) java.lang.reflect.Proxy.newProxyInstance(
                delegate.getClass().getClassLoader(),
                delegate.getClass().getInterfaces(), 
                invocationHandler);
	      proxy.invokeMethod("gogo");
        }

}
结果:

Object:DRealSubject,method:invokeMethod,argument:[gogo],cost(ms):1,result:success

通过上面测试例子,代理对象是通过Proxy.newProxyInstance()方法生成的,通过深入JDK的源码,其实,Proxy.newProxyInstance()是通过动态生成代理类的字节码,再由字节码反射成代理对象的,动态生成代理类的字节码,由下面方法生成:

byte[] sun.misc.ProxyGenerator.generateProxyClass(proxyName, Class<?>[] interfaces);//生成代理类字节码

动态生成代理类字节后,可通过类加载器的defineClass()方法加载类,当然下面ProxyClassLoader类是我自己测试写的,不是JDK的类。

private static class ProxyClassLoader extends ClassLoader{
		/**
		 * @param name The expected binary name of the class, or null if not known
		 * @param b The bytes that make up the class data. The bytes in positions off
		 * 			 through off+len-1 should have the format of a valid class file as
		 * 			 defined by The Java™ Virtual Machine Specification.
		 * @param off The start offset in b of the class data
		 * @param len The length of the class data
		 * @return
		 */
		public Class<?> defineClass0(String name, byte[] b, int off, int len){
			return super.defineClass(name, b, off, len);
		}
	}
加载得到类后,便可以通过反射方式生成类的对象。

代理类的构造方法需要传入一个InvocationHandler对象,也既是我们上面定义的DSubjectInvocationHandler类的对象,而InvocationHandler对象的构造函数则传入了委托接口的真实实现类DRealSubject,则在调用代理类对象时,也会通过反射的方式,调用委托接口的相关方法,其实生成的代理类对象结构如下:

public class DSubject$Proxy1 extends java.lang.reflect.Proxy implements DSubject{
	
	private static Method equalsMethod;
	private static Method hashCodeMethod;
	private static Method toStringMethod;
	private static Method invokeMethod;
	
	static{
		try {
			equalsMethod = Class.forName("java.lang.Object").getMethod("equals", new Class<?>[]{Class.forName("java.lang.Object")});
			hashCodeMethod = Class.forName("java.lang.Object").getMethod("hashCode", new Class<?>[0]);
			toStringMethod = Class.forName("java.lang.Object").getMethod("toString", new Class<?>[0]);
			invokeMethod = Class.forName("lam.design.pattern.proxy.dynamic.DSubject")
						.getMethod("invokeMethod", new Class<?>[]{Class.forName("java.lang.String")});
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public DSubject$Proxy1(InvocationHandler h) {
		super(h);
	}

	@Override
	public String invokeMethod(String argument) {
		try {
			return (String)h.invoke(this, invokeMethod, new Object[]{argument});
		} catch (Throwable e) {
			throw new UndeclaredThrowableException(e);
		}
	}
	
	@Override
	public final boolean equals(Object obj) {
		try {
			return ((Boolean)h.invoke(this, equalsMethod, new Object[]{obj})).booleanValue();
		} catch (Throwable e) {
			throw new UndeclaredThrowableException(e);
		}
	}
	
	@Override
	public final int hashCode() {
		try {
			return ((Integer)h.invoke(this, hashCodeMethod, null)).intValue();
		} catch (Throwable e) {
			throw new UndeclaredThrowableException(e);
		}
	}
	
	@Override
	public final String toString() {
		try {
			return (String)h.invoke(this, toStringMethod, null);
		} catch (Throwable e) {
			throw new UndeclaredThrowableException(e);
		}
	}

}

动态代理是设计模式-代理模式的一种

代理模式包含:静态代理和动态代理

代理模式可以参照点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值