JDK动态代理-源码分析

最近在深入学习代理模式
尝试了一下JDK动态代理的简单源码分析,从源码进行分析感觉对动态代理的实现更加清晰,特此记录
先分析一下JDk代理的实现。
条件: 代理人,被代理人,代理做的事
流程:获取被代理人信息生成代理实例完成代理工作

JDk代理中,代理人通过实现InvocationHandler来完成代理
先看看InvocationHandler做了什么。

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

通过源码我们不难看出,代理人通过实现invoke方法完成代理工作
因此,我们可以自定义一个InvocationHandler---->MyInvocationHandler

package com.Mrxuuu.st.proxy.custom.MyProxy;

import java.lang.reflect.Method;

public interface MyInvocationHandler {
	public Object invoke(Object proxy, Method method, Object[] args)
	        throws Throwable;
}

上面说了,代理人要完成代理首先得获取被代理人信息生成代理人实例
实现过程如下

	//代理对象先得获取被代理者的信息才能完成代理工作
	private Person target;
	
	//
	public Object getInstance(Person target)throws Exception{
		this.target=target;
		//获取被代理对象类信息
		Class<? extends Person> clazz = target.getClass();
		//实例化代理对象
		 Object instance = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
		 return instance;
	}

看看流程

 Object instance = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);

在获取代理信息后,通过Proxy.newProxyInstance(…)来获取实例
并且JDK代理生成了一个新的代理对象$Proxy0
在这里插入图片描述

我们通过字节码生成class文件 反编译看看$Proxy0都有些什么

import com.sun.proxy.*;
import java.lang.reflect.*;

public final class $proxy0 extends Proxy implements $Proxy0
{
    private static Method m1;
    private static Method m5;
    private static Method m2;
    private static Method m6;
    private static Method m11;
    private static Method m13;
    private static Method m0;
    private static Method m8;
    private static Method m12;
    private static Method m7;
    private static Method m10;
    private static Method m4;
    private static Method m9;
    private static Method m3;
    
    public $proxy0(final InvocationHandler invocationHandler) {
        super(invocationHandler);
    }
    
    public final boolean equals(final Object o) {
        try {
            return (boolean)super.h.invoke(this, $proxy0.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final InvocationHandler getInvocationHandler(final Object o) throws IllegalArgumentException {
        try {
            return (InvocationHandler)super.h.invoke(this, $proxy0.m5, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final String toString() {
        try {
            return (String)super.h.invoke(this, $proxy0.m2, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final Class getProxyClass(final ClassLoader classLoader, final Class[] array) throws IllegalArgumentException {
        try {
            return (Class)super.h.invoke(this, $proxy0.m6, new Object[] { classLoader, array });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final Class getClass() {
        try {
            return (Class)super.h.invoke(this, $proxy0.m11, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void notifyAll() {
        try {
            super.h.invoke(this, $proxy0.m13, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final int hashCode() {
        try {
            return (int)super.h.invoke(this, $proxy0.m0, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, $proxy0.m8, null);
        }
        catch (Error | RuntimeException | InterruptedException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void notify() {
        try {
            super.h.invoke(this, $proxy0.m12, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final Object newProxyInstance(final ClassLoader classLoader, final Class[] array, final InvocationHandler invocationHandler) throws IllegalArgumentException {
        try {
            return super.h.invoke(this, $proxy0.m7, new Object[] { classLoader, array, invocationHandler });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void wait(final long n) throws InterruptedException {
        try {
            super.h.invoke(this, $proxy0.m10, new Object[] { n });
        }
        catch (Error | RuntimeException | InterruptedException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final boolean isProxyClass(final Class clazz) {
        try {
            return (boolean)super.h.invoke(this, $proxy0.m4, new Object[] { clazz });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void wait(final long n, final int n2) throws InterruptedException {
        try {
            super.h.invoke(this, $proxy0.m9, new Object[] { n, n2 });
        }
        catch (Error | RuntimeException | InterruptedException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void doSth() {
        try {
            super.h.invoke(this, $proxy0.m3, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    static {
        try {
            $proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            $proxy0.m5 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getInvocationHandler", Class.forName("java.lang.Object"));
            $proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
            $proxy0.m6 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getProxyClass", Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"));
            $proxy0.m11 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getClass", (Class<?>[])new Class[0]);
            $proxy0.m13 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notifyAll", (Class<?>[])new Class[0]);
            $proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
            $proxy0.m8 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", (Class<?>[])new Class[0]);
            $proxy0.m12 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notify", (Class<?>[])new Class[0]);
            $proxy0.m7 = Class.forName("com.sun.proxy.$Proxy0").getMethod("newProxyInstance", Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler"));
            $proxy0.m10 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", Long.TYPE);
            $proxy0.m4 = Class.forName("com.sun.proxy.$Proxy0").getMethod("isProxyClass", Class.forName("java.lang.Class"));
            $proxy0.m9 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", Long.TYPE, Integer.TYPE);
            $proxy0.m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("doSth", (Class<?>[])new Class[0]);
        }
        catch (NoSuchMethodException ex) {
            throw new NoSuchMethodError(ex.getMessage());
        }
        catch (ClassNotFoundException ex2) {
            throw new NoClassDefFoundError(ex2.getMessage());
        }
    }
}

内容很简单,都是一些类里面的方法。也就是说,代理对象,读取了被代理类的所有信息,然后又新生成了一个类。 JDK代理也就是生成一个新的对象去帮助我原来的对象做事。
那么思路来了。 我们可以自己在读取被代理类的字节码后,自己生成一个新的代理类。然后自己编译,加载到JVM.这样的话,是不是自己就完成了一个JDK代理。

思路有了就好办了。
那么我们就可以开始自定义Proxy------->MyProxy
Proxy主要实现了代理实例的生成。

newProxyInstance(ClassLoader loader,
             Class<?>[] interfaces,
             MyInvocationHandler h)

从以上方法我们可以看出来。要实现新实例,我们还得有自己的ClassLoader
这里我们通过findClass来加载我们要生成的class.
到这里,分析步骤齐活。
说干就干。

首先定义自己的ClassLoader
//代码生成

public class MyClassLoader extends ClassLoader{

	private File baseDir;
	
	public MyClassLoader() {
	 String basePath=MyClassLoader.class.getResource("").getPath();
	 
	 this.baseDir=new File(basePath);
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		// TODO Auto-generated method stub
		System.out.println(name);
		String className=MyClassLoader.class.getPackage().getName()+"."+name;
		System.out.println(className);
		if(baseDir!=null) {
			File classFile=new File(baseDir,name.replaceAll("\\.", "/")+".class");
			System.out.println(classFile.getPath());
			if(classFile.exists()) {
				FileInputStream in=null;
				try {
					in=new FileInputStream(classFile);
					ByteArrayOutputStream 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) {
					// TODO: handle exception
				}finally {
					if(null!=in)
					{
						 try {
							in.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
                 
				}
			}
		}
		return null;
	}
}

目的是将我们生产的代理对象加载到JVM(这里使用findClass 而不是loadClass,大家可以去查查二者的区别)

我们再来看看自定义生产示例的方法

newProxyInstance(ClassLoader loader,
             Class<?>[] interfaces,
             MyInvocationHandler h)

现在该定义MyInvocationHandler

public interface MyInvocationHandler {
	public Object invoke(Object proxy, Method method, Object[] args)
	        throws Throwable;
}

好像我们需要定义的都已经齐全了。
再捋一捋我们说过的代理的大致流程
获取被代理类信息,然后生产代理对象,然后完成代理工作

既然定义完了,现在我们来看看怎么怎么生产示例对象
代码如下:
//生成代理对象代码

public class MyProxy{

	private static String  rn="\r\n";
	 public static Object newProxyInstance(MyClassLoader loader,
             Class<?>[] interfaces,
             MyInvocationHandler h) throws Exception {
		 
		//1.生成源代码
		 String proxySrx=generatorSrc(interfaces[0]);
		 //2.将代码输出到磁盘,作为Java文件
		String filePath= MyProxy.class.getResource("").getPath();
		File file=new File(filePath+"$Proxy0.java");
		FileWriter fw=new FileWriter(file);
		fw.write(proxySrx);
		fw.close();
		 //3.编译源代码,生成class 
		//获取编译器
		 JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
		 StandardJavaFileManager manager=compiler.getStandardFileManager(null, null, null);
		 Iterable iterable=manager.getJavaFileObjects(file);
		 CompilationTask task=compiler.getTask(null, manager, null, null, null, iterable);
		 task.call();
		 manager.close();
		 
		 //4. 动态加载到jvm 返回代理对象
		  Class proxyClass=loader.findClass("$Proxy0");
		  Constructor c=proxyClass.getConstructor(MyInvocationHandler.class);
		  return c.newInstance(h);
	 }
	 
	 //生成代理类
	 public static String  generatorSrc(Class<?> interfaces) {
		 StringBuffer src=new StringBuffer();
		 src.append("package com.Mrxuuu.st.proxy.custom.MyProxy;"+rn);
		 src.append("import java.lang.reflect.*;"+rn);
		 src.append("public final class $Proxy0 implements " +interfaces.getName()+"{"+rn);
		 src.append("MyInvocationHandler h;"+rn);
		 src.append("public $Proxy0(MyInvocationHandler h){"+rn);
		 src.append("this.h=h;"+rn);
		 
		 src.append("}"+rn);
		 
		 for(Method m:interfaces.getMethods())
		 {   
			 src.append("public"+" "+m.getReturnType().getName()+" "+m.getName()+"(){"+rn);
			 src.append("try {"+rn);
			 src.append("Method m="+interfaces.getName()+".class.getMethod(\""+m.getName()+"\",new Class[]{});"+rn);
			 src.append("this.h.invoke(this,m,null);"+rn);
//			 if(!m.getReturnType().equals("void")) {
//				 src.append("return ''");
//			 }
			 src.append("} catch (Throwable e) {}"+rn);
			 src.append("}"+rn);
		 }
		 src.append("}");
		 
		 return src.toString(); 
	 }
}

代码一长串,我们先来看看我的注释:
1.生成代理类的源代码
我们之前已经看过JDK代理过程中生成的代理类$proxy0
我们可以自定义 generatorSrc(Class<?> interfaces) 生成一个同样的代理类 $Proxy0
并保存为自定义的java文件。
2.编译源代码,生成class 动态加载到jvm
3.返回一个我们需要的代理对象
4.通过代理对象去完成代理工作。

em…代码不简单,但是思路很简单,关于JDK动态代理的简单源码分析与重写就到这

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值