JDK动态代理使用方法及源码解析

189 阅读6分钟

spring 和 mybatis 都用到了代理,在学习之前先扒一下jdk动态代理。

静态代理

可以简单理解为中介。
场景:中介在消费者和厂家之间赚取差价。

public interface IManufacture {

	/**
	 * 制造
	 *
	 * @return {@link Object}
	 */
	Object manufacture();
}
public class ManufactureFactory implements IManufacture{

	/**
	 * 制造
	 *
	 * @return {@link Object}
	 */
	@Override
	public Object manufacture() {
		return "制造工厂";
	}

}
public class StaticProxy implements IManufacture {

	private ManufactureFactory factory;

	StaticProxy() {
	}

	public StaticProxy(ManufactureFactory factory) {
		this.factory = factory;
	}

	/**
	 * 制造
	 *
	 * @return {@link Object}
	 */
	@Override
	public Object manufacture() {
		factory.manufacture();
		return getSpread();
	}

	private String getSpread() {
		return "静态代理增强";
	}
}
// 厂家直销
@Test
public void proxyTest01() {
	IManufacture manufacture = new ManufactureFactory();
	System.out.println(manufacture.manufacture());
}
// 中介
@Test
public void proxyTest02() {
	IManufacture manufacture = new StaticProxy(new ManufactureFactory());
	System.out.println(manufacture.manufacture());
}

测试结果:
image.png
image.png

可以看到,静态代理做的事情就是在原有逻辑上添加自己的逻辑。
问题: 中介现在只对一家工厂做代理销售,如果格局大一点,承包更多的厂家。
如果用静态代理的方式,需要定义更多的静态代理类实现厂家接口,这么做可以实现,但是类有点多,主要是不太优雅。。。看看动态代理又是如何实现的。


动态代理

上面把静态代理当做是中介,如果对N个厂家做代理,需要创建N个代理类。
这N个代理各自做各自的业务,突然有一天,云朵姐要去割双眼皮,但是下午要和客户签合同,于是就让优雅哥帮忙,优雅哥动了一下脑子:“我们何不成立一个中介公司嘞?”,于是优雅中介成立了。

优雅中介就可以看做是 动态代理 ,消费者需要某厂家的产品时,优雅中介就会派出对应的中介进行服务(这个过程就是创建动态代理的过程),优雅中介也是一个 代理工厂

public class DynamicProxy implements InvocationHandler {

	private Object o;

	DynamicProxy() {
	}

	public DynamicProxy(Object o) {
		this.o = o;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		method.invoke(o, args);
		return getSpread();
	}

	// 创建代理
	public Object createProxy() {
		return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
	}

	private String getSpread() {
		return "动态代理增强";
	}
}

测试结果:

@Test
public void proxyTest03() {
	DynamicProxy dynamicProxy = new DynamicProxy(new ManufactureFactory());
	IManufacture manufacture = (IManufacture) dynamicProxy.createProxy();
	System.out.println(manufacture.manufacture());
}

image.png

JDK动态代理源码解析

其实原理上面已经说了,无非就是创建代理类,然后调用代理类的方法,体现到代码里面又是如何实现的?

生成代理类

// 创建代理
public Object createProxy() {
	return Proxy.newProxyInstance(o.getClass().getClassLoader(),
								  o.getClass().getInterfaces(),
								  this);
}
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
									  Class<?>[] interfaces,
									  InvocationHandler h)
	throws IllegalArgumentException{
	Objects.requireNonNull(h);

	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信息
	Class<?> cl = getProxyClass0(loader, intfs);

	/*
     * Invoke its constructor with the designated invocation handler.
	   
     */
	try {
		...
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		... 
		// 通过反射生成代理类
		return cons.newInstance(new Object[]{h});
	} ...
	}

入参:

  • ClassLoader loader 厂家类的 类加载器
  • Class<?>[] interfaces 厂家类实现的接口
  • InvocationHandler h 厂家对象

18 行:生成代理类的Class
26 行:拿到代理类的Class的构造方法
31 行:反射生成代理对象

private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
	if (interfaces.length > 65535) {
		throw new IllegalArgumentException("interface limit exceeded");
	}

	// If the proxy class defined by the given loader implementing
	// the given interfaces exists, this will simply return the cached copy;
	// otherwise, it will create the proxy class via the ProxyClassFactory
	return proxyClassCache.get(loader, interfaces);
}

3~5 行:一个小知识点,一个类最多只能实现65535个接口

public V get(K key, P parameter) {

	...

	// create subKey and retrieve the possible Supplier<V> stored by that
	// subKey from valuesMap
	Object subKey = Objects.requireNonNull(
		subKeyFactory.apply(key, parameter)
	);
	Supplier<V> supplier = valuesMap.get(subKey);
	Factory factory = null;

	...
}

先从缓存获取,主要看创建的过程。
8 行:创建代理

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

	Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
	for (Class<?> intf : interfaces) {
		/*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
		Class<?> interfaceClass = null;
		try {
			interfaceClass = Class.forName(intf.getName(), false, loader);
		} catch (ClassNotFoundException e) {
		}
		if (interfaceClass != intf) {
			throw new IllegalArgumentException(
				intf + " is not visible from class loader");
		}
		/*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
		if (!interfaceClass.isInterface()) {
			throw new IllegalArgumentException(
				interfaceClass.getName() + " is not an interface");
		}
		/*
                 * Verify that this interface is not a duplicate.
                 */
		if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
			throw new IllegalArgumentException(
				"repeated interface: " + interfaceClass.getName());
		}
	}

	String proxyPkg = null;     // package to define proxy class in
	int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

	/*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
	for (Class<?> intf : interfaces) {
		int flags = intf.getModifiers();
		if (!Modifier.isPublic(flags)) {
			accessFlags = Modifier.FINAL;
			String name = intf.getName();
			int n = name.lastIndexOf('.');
			String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
			if (proxyPkg == null) {
				proxyPkg = pkg;
			} else if (!pkg.equals(proxyPkg)) {
				throw new IllegalArgumentException(
					"non-public interfaces from different packages");
			}
		}
	}

	if (proxyPkg == null) {
		// if no non-public proxy interfaces, use com.sun.proxy package
		proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
	}

	/*
     * Choose a name for the proxy class to generate.
     */
	// proxyClassNamePrefix = "$Proxy"
	long num = nextUniqueNumber.getAndIncrement();
	String proxyName = proxyPkg + proxyClassNamePrefix + num;

	/*
             * Generate the specified proxy class.
             */
	byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
		proxyName, interfaces, accessFlags);
	try {
		return defineClass0(loader, proxyName,
							proxyClassFile, 0, proxyClassFile.length);
	} catch (ClassFormatError e) {
		/*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
		throw new IllegalArgumentException(e.toString());
	}
}

这个apply()就是具体生成代理类Class的地方。
62 行:设置类路径
69 行:设置类名:"$Proxy" + long数字
75 行:把代理类Class信息写入byte数组中, defineClass0()是个native方法,这就走到头了,可以把byte数组输出看一下

@Test
public void proxyTest03() {
	// 目标类
	IManufacture manufactureFactory = new ManufactureFactory();
	// 代理工厂
	DynamicProxy dynamicProxy = new DynamicProxy(manufactureFactory);
	// 代理
	IManufacture proxy = (IManufacture) dynamicProxy.createProxy();
	System.out.println(proxy.manufacture());
	// 输出代理类信息
	getProxyClassInfo(IManufacture.class, proxy.getClass().getSimpleName());
}

private void getProxyClassInfo(Class clazz, String proxyName) {
	byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
		proxyName, new Class[]{clazz});
	// 输出到和厂家对象相同的路径
	String path = clazz.getResource(".").getPath();
	FileOutputStream out = null;
	try {
		out = new FileOutputStream(path + proxyName + ".class");
		out.write(proxyClassFile);
		out.flush();
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		try {
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.springframework.nineq.jdk8.proxy.IManufacture;

public final class $Proxy12 extends Proxy implements IManufacture {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy12(InvocationHandler var1) throws  {
        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 Object manufacture() throws  {
        try {
            return (Object)super.h.invoke(this, m3, (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 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"));
            m3 = Class.forName("org.springframework.nineq.jdk8.proxy.IManufacture").getMethod("manufacture");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

和静态代理一样,动态代理和目标类(厂家类)实现了相同的接口,也就有了同样的实现方法 manufacture()

调用代理类方法

代理类对象已经有了,再看一下调用。

调用肯定是调用代理对象的 manufacture()方法,看代理类的manufacture()方法:

// 制造方法
public final Object manufacture() throws  {
	try {
		return (Object)super.h.invoke(this, m3, (Object[])null);
	} catch (RuntimeException | Error var2) {
		throw var2;
	} catch (Throwable var3) {
		throw new UndeclaredThrowableException(var3);
	}
}

4 行:super.h.invoke(),那就是Proxy类的 h 属性的 invoke(),h 又是什么?

还记得上面创建代理最开始的地方么,传了三个参数,第三个参数就是 h,也就是我们的代理工厂 DynamicProxy(InvocationHandler 的实现类)
image.png
最终会调用到 DynamicProxy#invoke(Object proxy, Method method, Object[] args)

public class DynamicProxy implements InvocationHandler {

	private Object o;

	DynamicProxy() {
	}

	public DynamicProxy(Object o) {
		this.o = o;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		method.invoke(o, args);
		return getSpread();
	}

	public Object createProxy() {
		return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
	}

	private String getSpread() {
		return "动态代理增强";
	}
}

15 行:也就是我们自己写的这个方法,逻辑就很清楚了吧。

JDK动态代理的使用方法

  1. 首先确认目标类,也就是需要被代理的类
  2. 创建InvocationHandler实现类,在invoke方法写自己逻辑即可。

总结

代理就是在不改变原有代码的前提下,加上我们自己的功能。
JDK动态代理,需要实现InvocationHandler接口,重写invoke方法。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。