前言
Java動態(tài)代理通過反射的機制實現(xiàn)在運行時,基于傳入的指定一組接口及委托類對象,動態(tài)的產(chǎn)生代理類,代理類負責將所有的方法調(diào)用分派到委托對象上反射執(zhí)行。動態(tài)代理類的創(chuàng)建十分簡單:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
或者
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
有動態(tài)代理,那一定有靜態(tài)代理。所以我們先從靜態(tài)代理看起,一步步分析Java的動態(tài)代理機制。
靜態(tài)代理
說到靜態(tài)代理,其實就是我們手工對代理模式的實現(xiàn)。代理模式是什么呢?
代理是一種常用的設(shè)計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負責為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進行消息被委托類執(zhí)行后的后續(xù)處理。
代理模式的UML圖如下所示:

為了保持行為的一致性,代理類和委托類通常會實現(xiàn)相同的接口,所以在訪問者看來兩者沒有絲毫的區(qū)別。通過代理類這中間一層,能有效控制對委托類對象的直接訪問,也可以很好地隱藏和保護委托類對象,同時也為實施不同控制策略預(yù)留了空間,從而在設(shè)計上獲得了更大的靈活性。
我們看一個簡單的代理模式的例子:
public interface Bird {
public void fly();
}
public class RealBird implements Bird {
private String name;
public RealBird(String name) {
this.name = name;
}
public void fly() {
System.out.println(String.format("%s is flying...", name));
}
}
public class ProxyBird implements Bird{
private String name;
private Bird bird;
public ProxyBird(String name) {
this.name = name;
}
public void fly() {
if (null == bird){
this.bird = new RealBird(name);
}
bird.fly();
}
}
public class ProxyExample {
public static void main(String[] args){
Bird eagle = new RealBird("eagle");
Bird swan = new ProxyBird("swan");
eagle.fly();
swan.fly();
}
}
eagle is flying...
swan is flying...
代理模式使得代理類控制了客戶端對委托類的訪問,這使得我們可以在代理類中做一些其他的操作,如日志記錄、統(tǒng)計、緩存等,這些都是對用戶隱藏的。同時代理類實現(xiàn)與委托類相同接口,代理模式的使用對用戶來說是透明的。
Java動態(tài)代理使得我們不必手寫大量代理類,通過反射方式,在使用時動態(tài)的生成代理類。
動態(tài)代理
相關(guān)類與接口
動態(tài)代理的核心就在于java.lang.reflect.Proxy類與java.lang.reflect.InvocationHandler這個接口。
- Proxy類:它是Java動態(tài)代理的生成器,它提供了以下靜態(tài)方法來生成動態(tài)代理類。
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces);//根據(jù)傳入的類加載器、接口生成代理類對象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h);//根據(jù)傳入的類加載器、接口、調(diào)用處理器動態(tài)生成代理類
public static InvocationHandler getInvocationHandler(Object proxy);//獲取代理類對應(yīng)的調(diào)用處理器
- InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args);//調(diào)用處理器接口,每個動態(tài)類必須關(guān)聯(lián)一個InvocationHandler,通過反射在代理類上執(zhí)行傳入的方法。
源碼分析
我們通過一個簡單的動態(tài)代理的例子來具體分析動態(tài)代理機制。
public interface Subject {
public void doSomething();
}
public class RealSubject implements Subject{
public void doSomething() {
System.out.println("do something...");
}
}
public class ProxyInvocationHandler implements InvocationHandler{
private Object proxies;
public ProxyInvocationHandler(Object proxies){
this.proxies = proxies;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
//此處可以做一些方法調(diào)用的前置操作
PrintUtil.print(String.format("proxy:%s,method:%s,args:%s", proxies,method,args));
result = method.invoke(proxies, args);
//此處可以做一些方法調(diào)用的后置操作
return result;
}
}
public class ProxyTest {
public static void main(String[] args){
Subject realSubject = new RealSubject();//實際對象
Subject subject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, new ProxyInvocationHandler(realSubject));
subject.doSomething();
}
}
do something...
從上面的簡單例子我們可以總結(jié)出使用Java的動態(tài)代理的幾個步驟:
我們從Proxy類的靜態(tài)方法newProxyInstance開始追蹤起,源碼如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
if (h == null) {
throw new NullPointerException();
}
final Class<?>[] intfs = interfaces.clone();//復(fù)制interfaces接口數(shù)組
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);//接口權(quán)限檢查
}
/*
* 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);//獲取代理類的構(gòu)造器對象
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());
}
}
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {//該代理類代理的委托類的接口不能超過65536個
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
//從緩存中獲取 由對應(yīng)的ClassLoader加載的實現(xiàn)了對應(yīng)接口的代理類,如果沒有緩存,則先創(chuàng)建一個代理類,然后緩存起來。
return proxyClassCache.get(loader, interfaces);//
}
/**
* a cache of proxy classes
* proxyClassCache 是Proxy實例的私有變量,是一個由WeakCache構(gòu)成的緩存結(jié)構(gòu)
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
WeakCache的get操作源碼如下:
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// 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;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
而代理類的生成是通過ProxyClassFactory來完成的。生成代理類的核心邏輯是在apply方法中,我們繼續(xù)分析:
/**
* 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);
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
/*
* 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)) {
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.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);//此處生成代理類字節(jié)碼文件
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);//類加載器把該類的字節(jié)碼加載進內(nèi)存升策劃那個該類的class對象
} 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());
}
}
}
最后是通過JDK自帶的字節(jié)碼生成工具類ProxyGenerator,根據(jù)傳入的代理類名以及代理類需要實現(xiàn)的接口來完成代理類字節(jié)碼文件的生成:
public static byte[] generateProxyClass(String paramString, Class[] paramArrayOfClass) {
ProxyGenerator localProxyGenerator = new ProxyGenerator(paramString, paramArrayOfClass);
byte[] arrayOfByte = localProxyGenerator.generateClassFile();
if (saveGeneratedFiles)
AccessController.doPrivileged(new PrivilegedAction(paramString, arrayOfByte) {
public Void run() {
try {
FileOutputStream localFileOutputStream = new FileOutputStream(
ProxyGenerator.access$000(this.val$name) + ".class");
localFileOutputStream.write(this.val$classFile);
localFileOutputStream.close();
return null;
} catch (IOException localIOException) {
throw new InternalError("I/O exception saving generated file: " + localIOException);
}
}
});
return arrayOfByte;
}
generateProxyClass方法生成代理類的核心在于generateClassFile方法,該方法的主要工作就是根據(jù)JAVA字節(jié)碼規(guī)范,根據(jù)我們設(shè)定的目的-生成一個帶有一些接口的代理類,最終在內(nèi)存中生成該代理類的字節(jié)碼流,然后寫入磁盤,最終該代理類就生成了。然后類加載器加載該字節(jié)碼,我們就可以在程序中使用該代理類了。
注:我們在generateProxyClass方法中可以看到一點,當saveGeneratedFiles為true時,我們才會執(zhí)行后面的把生成的代理類寫到磁盤存儲下來。但saveGeneratedFiles的值是在哪里設(shè)置的呢?查找ProxyGenerator類,發(fā)現(xiàn):
private static final boolean saveGeneratedFiles;
static {
saveGeneratedFiles = ((Boolean) AccessController
.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
try {
hashCodeMethod = Object.class.getMethod("hashCode", new Class[0]);
equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class });
toStringMethod = Object.class.getMethod("toString", new Class[0]);
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
}
ProxyGenerator類初始化的時候,會去系統(tǒng)屬性里查找‘sun.misc.ProxyGenerator.saveGeneratedFiles’屬性的val并賦值給saveGeneratedFiles。所以很清楚了,我們只需要在系統(tǒng)Property里設(shè)置 ‘sun.misc.ProxyGenerator.saveGeneratedFiles’屬性為true,我們使用的動態(tài)代理類就會落地到磁盤上了。
我們運行一下該代理類:
public class ProxyTest {
public static void main(String[] args){
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Subject sub = new RealSubject();
Subject proxy = (Subject)Proxy.newProxyInstance(sub.getClass().getClassLoader(), sub.getClass().getInterfaces(), new ProxyInvocationHandler(sub));
proxy.doSomething();
}
}
報錯:
Exception in thread "main" java.lang.InternalError: I/O exception saving generated file: java.io.FileNotFoundException: com\sun\proxy$Proxy0.class (系統(tǒng)找不到指定的路徑。)
手動創(chuàng)建目錄,得到落地的動態(tài)代理類$Proxy0字節(jié)碼文件,反編譯得到:
public final class $Proxy0 extends Proxy
implements Subject
{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void doSomething()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("com.xxxx.book.zzm.chap7.proxy.Subject").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
總結(jié)
以上就是我們對Java動態(tài)代理機制的分析,通過源碼分析,我們知道了jdk是通過代理類生成器生成了代理類。通過對全局屬性‘sun.misc.ProxyGenerator.saveGeneratedFiles’的設(shè)置,該動態(tài)類可以落地到磁盤。
參考
- jdk1.7源碼