本篇將從源碼層面分析,JDK代理的具體實現(xiàn)方式。
摘錄源碼版本:JDK 1.8
概述
我們知道,在Spring AOP 中,創(chuàng)建代理有兩種方式,jdk動態(tài)代理與cglib動態(tài)代理。本篇先講一下JDK動態(tài)代理的低層原理。
JDK動態(tài)代理是使用了Java的反射機制,利用Proxy生成實現(xiàn)了目標(biāo)接口的代理類。
大綱:
- JDK 動態(tài)代理實現(xiàn)步驟
- JDK 動態(tài)代理使用方法
- InvocationHander
- Proxy.newProxyInstance
- Proxy 生成代理類的源碼解析
JDK Proxy 實現(xiàn)原理
關(guān)鍵接口: java.lang.reflect.InvocationHandler
關(guān)鍵類: java.lang.reflect.Proxy
JDK動態(tài)代理實現(xiàn)步驟
JDK實現(xiàn)動態(tài)代理簡單來說有五個步驟:
1,創(chuàng)建自定義InvocationHander,通過繼承 InvocationHandler接口,來實現(xiàn)自定義的 invoke操作。(AOP邏輯就在 invoke() 方法中)
2,通過 Proxy.newProxyInstance 方法,生成并獲取代理類的實例對象。
3,在 Proxy.newProxyInstance 方法中,通過反射,獲取到代理類的構(gòu)造方法,方法簽名為 getConstructor(InvocationHandler.class)
4,通過構(gòu)造函數(shù)生成Proxy類的對象,并且生成時,將自定義的InvocationHandler實例對象作為參數(shù)傳入。
5,通過代理對象調(diào)用目標(biāo)方法。
JDK動態(tài)代理的使用
通過以下代碼,可以看到是如何利用 InvocationHander 和 Proxy 生成代理對象并且使用代理的。
示例代碼如下:
// 自定義 InvocationHandler (也可以看做是代理)
public class JDKProxy implements InvocationHandler {
// 要代理的目標(biāo)實例
private Object proxyObject;
public JDKProxy(Object proxyObject) {
this.proxyObject = proxyObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// do something
Object ret = null; //方法返回值
System.out.println("JDK Proxy --- 調(diào)用前 --- 調(diào)用方法是:"+method.getName() + "---參數(shù)是:"+ GsonUtil.toJson(args));
ret = method.invoke(proxyObject, args); //對目標(biāo)實例調(diào)用invoke方法
System.out.println("JDK Proxy --- 調(diào)用后");
return ret;
}
}
// 生成代理類的工廠方法
public static Object createJDKProxyInstance(Object proxyObject){
JDKProxy jdkProxy = new JDKProxy(proxyObject);
return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(), proxyObject.getClass().getInterfaces(), jdkProxy);
}
// 具體使用的代碼
DemoManager demoProxy = (DemoManager) ProxyFactory.createJDKProxyInstance(new DemoManagerCustom());
InvocationHandler
先來看看 InvocationHandler 這個接口
注釋是這么寫的
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
InvocationHandler 是一個接口,每一個需要 自定義 方法調(diào)用處理器的 代理實例都要實現(xiàn)這個接口。
每一個代理實例都關(guān)聯(lián)著一個 invocation handler。當(dāng)代理實例的方法被調(diào)用的時候,這個方法就會編碼和轉(zhuǎn)發(fā)到 invocation handler的 invoke 方法調(diào)用。
這個接口只有一個方法:invoke()
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
這個方法接受三個參數(shù):
- proxy:指我們生成的代理對象實例
- method:當(dāng)前調(diào)用的method對象
- args:調(diào)用method的方法參數(shù)列表。
Proxy
Proxy類,就是用來創(chuàng)建動態(tài)代理對象的類。類注釋如下:
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods
Proxy 提供了創(chuàng)建動態(tài)代理類和實例的靜態(tài)方法,同時這些動態(tài)代理類的超類也會在這些方法里被創(chuàng)建。
Proxy類提供了許多方法,動態(tài)代理用的方法是 newProxyInstance,使用方式在示例代碼中已經(jīng)給出。
我們可以看看源碼中方法的定義:
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class to implement
* @param h the invocation handler to dispatch method invocations to
**/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
該方法接收三個參數(shù)
loader:一個ClassLoader對象,定義了由哪個ClassLoader來對生成的代理類進行加載。
interfaces:代理類的繼承接口數(shù)組,表示的是我需要給代理的類提供的接口,如果我提供了接口給這個代理類,那么這個代理對象就聲稱實現(xiàn)了這些接口,那么我們就可以調(diào)用這些接口的方法。
(JDK動態(tài)代理只能對實現(xiàn)了接口的目標(biāo)對象代理的根本原因)h:方法調(diào)用轉(zhuǎn)發(fā)的目的 invocation hander 實例。表示這個代理對象會關(guān)聯(lián)到哪個 invocation handler 上。
JDK動態(tài)代理原理
通過上面 InvocationHandler 和 Proxy 的介紹。那么動態(tài)代理的基本原理就可以捋清了:
1)通過繼承 InvocationHander,來自定義一個 invocation hander。這個hander 保存了一個代理目標(biāo)對象的引用。
2)在實現(xiàn) invoke() 方法中,我們把接收到的方法調(diào)用請求,用proxyObject來執(zhí)行。即 method.invoke(proxyObject, args),得到代理對象的方法調(diào)用結(jié)果并返回。
3)在 invoke 方法中嵌入 AOP 相關(guān)的處理邏輯。這樣就實現(xiàn)了目標(biāo)方法調(diào)用時,橫切邏輯的執(zhí)行。
4)代理對象的生成,使用 Proxy.newProxyInstance() 方法生成,傳入的三個參數(shù)依次為,目標(biāo)對象的類加載器,目標(biāo)對象實現(xiàn)的接口列表,invocation handler 實例。
5)這樣生成的代理對象,就是繼承了目標(biāo)對象接口列表的代理類的實例對象。
使用向上轉(zhuǎn)型的方式,把對象聲明為接口的實例。并且和目標(biāo)對象有一樣的方法。
6)利用多態(tài)的機制,對接口對象的方法調(diào)用,會動態(tài)鏈接到代理對象的方法調(diào)用,然后又會轉(zhuǎn)發(fā)到我們自定義 invocation hander 中,對 invoke 函數(shù)的調(diào)用,實現(xiàn)橫切邏輯的調(diào)用。
源碼解析
通過Debug模式查看代理對像的類型可以發(fā)現(xiàn)
Proxy.newProxyInstance() 生成的代理類名稱為 com.sun.proxy.$Proxy0。這個類是JVM在運行時動態(tài)生成的,以$開頭,Proxy為中間,最后的序號表示類對象的序號。
(生成代理類的邏輯可以參考 Proxy.ProxyClassFactory,下面放出了源碼)
其中有一個公共的構(gòu)造器:
public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler),
那么可以知道,我們的代理實例對象,就是用這個構(gòu)造器生成的。
如圖:

Proxy.newProxyInstance
/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h); //h 不能為空,所以 InvocationHandler 是必須的
final Class<?>[] intfs = interfaces.clone(); //對象拷貝
final SecurityManager sm = System.getSecurityManager();
if (sm != null) { //校驗是否有權(quán)限創(chuàng)建一個代理類
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.
* 調(diào)用這個代理類的構(gòu)造器,傳入指定的 invocation handler 對象
*/
try {
if (sm != null) { //權(quán)限校驗,不細講
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 獲取參數(shù)是 InvocationHander.class 類型的構(gòu)造器
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// 如果這個構(gòu)造器不是公有的,則把修飾符改為公有。
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 調(diào)用構(gòu)造器,生成代理類的對象并且返回
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
getProxyClass0
在上面方法中可以看到,生成動態(tài)代理類的方法,是調(diào)用了
getProxyClass0 方法。
而其中關(guān)鍵在于 proxyClassCache.get(loader, interfaces);
根據(jù)該方法的注釋可以明白,這里有一個代理類的緩存,如果這個代理類已經(jīng) 有指定類加載器并且繼承了這些接口,那么將直接返回生成的代理類,否則將由ProxyClassFactory生成代理類。
那么看看這個方法的源碼:
/**
* a cache of proxy classes(一個已經(jīng)生成了代理類的緩存)
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
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);
}
ProxyClassFactory
創(chuàng)建類的核心還是在 ProxyClassFactory 類中。
可以看到 ProxyClassFactory 實現(xiàn)了函數(shù)式接口 BiFunction。(JDK8)
入?yún)⑹?類加載器(ClassLoader) 和 接口數(shù)組(Class<?>[])
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
//(所有生成的代理類前綴都是 $Proxy)
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
// (代理類的生成序號)
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
// 遍歷接口數(shù)組,校驗:
// 1)接口是否能找到,加載到的實例是否和傳入的接口實例一樣
// 2)校驗加載的實例是否是一個接口
// 3)接口去重
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.
* 生成代理類的名字
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 生成類的字節(jié)碼,然后通過本地方法 defineClass0 生成代理類
*/
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());
}
}
}
(如果有什么錯誤或者建議,歡迎留言指出)
(本文內(nèi)容是對各個知識點的轉(zhuǎn)載整理,用于個人技術(shù)沉淀,以及大家學(xué)習(xí)交流用)
參考資料:
深度剖析JDK動態(tài)代理機制(JDK Proxy源碼分析)
java動態(tài)代理機制詳解
靜態(tài)代理和動態(tài)代理的理解
Spring源碼剖析——AOP實現(xiàn)原理 (Spring 使用JDK Proxy )
SpringAOP兩種方式——JDKDynamicAopProxy和cglib2AopProxy源碼解析 (Spring 使用JDK Proxy )