JAVA 设计模式 之 动态代理

原创
2017/05/06 09:50
阅读数 180

JAVA的设计模式-JDK动态代理:实现控制 被代理类的方法执行前,执行后来做你想做的事。

1.自写代理模式示例代码

接口
public interface Subject{

	public void doSomeThing();
	
}
实现类
public class RealObject implements Subject{

	@Override
	public void doSomeThing() {
		System.out.println("doSomeThing..");
	}

}
自写代理类
public class SimpleProxy {
	Object obj = null;
	public SimpleProxy(Object obj){
		this.obj = obj;
	}
	public void doSomeThing(){
		System.out.println("SimpleProxy doSomeThing start...");
		this.obj.doSomeThing();
		System.out.println("SimpleProxy doSomeThing end...");
	}
}
执行
public class TestProxy {

	public static void main(String[] args) {
		Subject obj = new RealObject();
		SimpleProxy simplePro = new SimpleProxy(obj);
		simplePro.doSomeThing();
	}
}
控制台打印结果
SimpleProxy doSomeThing start...
doSomeThing..
SimpleProxy doSomeThing end...

** 2:实现 InvocationHandler 接口 (充当SimpleProxy )来实现代理模式 示例代码**

接口
public interface Subject {

	public void doSomeThing();
	
}
实现类
public class RealObject implements Subject{

	@Override
	public void doSomeThing() {
		System.out.println("doSomeThing..");
	}

}
代理类
public class DynamicProxy implements InvocationHandler {

	Object obj = null;
	public DynamicProxy(Object obj){
		this.obj = obj;
	}
	@Override
	public java.lang.Object invoke(java.lang.Object proxy, Method method,
			java.lang.Object[] args) throws Throwable {
		System.out.println("proxy class:"+proxy.getClass());
		System.out.println("proxy name:"+proxy.getClass().getSimpleName());
		System.out.println("method:"+method.getName());
		return method.invoke(this.obj, args);
	}

}
测试
public class TestProxy {

	public static void main(String[] args) {

		Subject sub = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
				new Class[]{Subject.class}, new DynamicProxy(new RealObject()));
		sub.doSomeThing();
	}
}

控制台输出:
proxy class:class com.sun.proxy.$Proxy0
proxy name:$Proxy0
method:doSomeThing
doSomeThing..

The last 分析源代码,实现接口InvocationHandler 具体做了什么。

昨天没有找到源码,,,,表示心也很累,,,, 进入Proxy.newProxyInstance() 方法

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

主要的是getProxyClass0()方法的调用,一直跟进,直接到代理工厂类ProxyClassFactory的apply() 其中多的是一些判断,无意看到了一个 IdentityHashMap集合。。呵呵 接着往下走,有一个 ProxyGenerator.generateProxyClass(proxyName, interfaces) proxyName是生产的代理对象类,interfaces是被代理的接口,并返回一个byte[]字节数组

  public static byte[] generateProxyClass(String paramString, Class[] paramArrayOfClass)
  {
    ProxyGenerator localProxyGenerator = new ProxyGenerator(paramString, paramArrayOfClass);
    final byte[] arrayOfByte = localProxyGenerator.generateClassFile();
    if (saveGeneratedFiles) {
      AccessController.doPrivileged(new PrivilegedAction()
      {
        public Void run()
        {
          try
          {
            FileOutputStream localFileOutputStream = new FileOutputStream(ProxyGenerator.dotToSlash(this.val$name) + ".class");
            
            localFileOutputStream.write(arrayOfByte);
            localFileOutputStream.close();
            return null;
          }
          catch (IOException localIOException)
          {
            throw new InternalError("I/O exception saving generated file: " + localIOException);
          }
        }
      });
    }
    return arrayOfByte;
  }

返回的字节数组是实现了接口interfaces,类名称为proxyName的类, JDK根据既定规则直接生成class文件,用native方法加载了这个类,最终产生了一个实现了一个接口的类

    private static native Class defineClass0(ClassLoader loader, String name,
                                             byte[] b, int off, int len);

_传入的 new DynamicProxy(new RealObject()) _ 回到Proxy.newProxyInstance 的最后一行

 return cons.newInstance(new Object[] {h} );

new DynamicProxy(new RealObject()) 可以理解是为生成的proxyName类转入的一个参数。

。。。。。在写这个的时候了解到CGLIB 也可以实现动态代理。只是产生动态代理对象时不用接口类! 写在离职前的几天。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部