主要API類是:
```
Proxy.newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class<?>[] interfaces,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? InvocationHandler h)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? throws IllegalArgumentException
返回一個指定接口的代理類實例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序。此方法相當于:
? ? Proxy.getProxyClass(loader, interfaces).
? ? ? ? getConstructor(new Class[] { InvocationHandler.class }).
? ? ? ? newInstance(new Object[] { handler });
```
```
Proxy.newProxyInstance 拋出 IllegalArgumentException,原因與 Proxy.getProxyClass 相同。
參數(shù):
loader - 定義代理類的類加載器
interfaces - 代理類要實現(xiàn)的接口列表
h - 指派方法調(diào)用的調(diào)用處理程序
返回:
一個帶有代理類的指定調(diào)用處理程序的代理實例,它由指定的類加載器定義,并實現(xiàn)指定的接口
拋出:
IllegalArgumentException - 如果違反傳遞到 getProxyClass 的參數(shù)上的任何限制
NullPointerException - 如果 interfaces 數(shù)組參數(shù)或其任何元素為 null,或如果調(diào)用處理程序 h 為 null
```
先聲明一個接口
```
package com.czq.proxy;
public interface IPackageManager {
? ? String getPackageInfo() ;
}
```
實現(xiàn)該接口
```
package com.czq.proxy;
public class PackageManagerImpl implements IPackageManager {
? ? @Override
? ? public String getPackageInfo() {
? ? ? ? String s = "com.czq.proxy";
//? ? ? ? System.out.println(s);
? ? ? ? return s;
? ? }
? ? @Override
? ? public String toString() {
? ? ? ? return "PackageManagerImpl";
? ? }
}
```
實現(xiàn)InvocationHandler 接口,關(guān)鍵之處在這
```
package com.czq.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PackageManagerWoker implements InvocationHandler {
? ? private Object mTarget = null;
? ? public PackageManagerWoker(Object target) {
? ? ? ? super();
? ? ? ? this.mTarget = target;
? ? }
? ? @Override
? ? public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
? ? ? ? System. out.println("1" );
? ? ? ? System. out.println("method:" +method);
? ? ? ? if (args != null) {
? ? ? ? ? ? for (int i = 0; i < args.length; i++) {
? ? ? ? ? ? ? ? System. out.println("args[" + i + "]:" + args[i]);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? Object result = method.invoke( mTarget, args);
? ? ? ? System. out.println("2" );
? ? ? ? return result;? ? ?
? ? }
```
測試:
```
package com.czq.proxy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
public class Test {
? ? public static void main(String[] args) {
? ? ? ? // 從源碼中得知,設(shè)置這個值,可以把生成的代理類,輸出出來。
? ? ? ? System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
? ? ? ? IPackageManager pkgManger = new PackageManagerImpl();
//? ? ? ? System.out.println("pkgManger.toString:"+pkgManger.toString());
? ? ? ? PackageManagerWoker woker = new PackageManagerWoker(pkgManger);
? ? ? ? IPackageManager pm = (IPackageManager) Proxy.newProxyInstance(pkgManger.getClass().getClassLoader(), pkgManger
? ? ? ? ? ? ? ? .getClass().getInterfaces(), woker);
? ? ? //? System.out.println("pm.getName:" +pm.getClass().getName())
? ? ? ? System. out.println("pm.toString:" +pm.toString());
? ? ? ? System.out.println(pm.getPackageInfo());
? ? }
}
```
輸出結(jié)果如下:
```
1
method:public java.lang.String java.lang.Object.toString()
2
pm.toString:PackageManagerImpl
1
method:public abstract java.lang.String com.czq.proxy.IPackageManager.getPackageInfo()
2
com.czq.proxy
```
得出結(jié)論:
pm.getPackageInfo()方法會走到PackageManagerWoker的invoke方法。
思考問題:
PackageManagerWoker不繼承IPackageManager。不能強轉(zhuǎn)成IPackageManager。
也就是pm對象不是PackageManagerWoker對象。
那pm 是哪個對象,是什么類呢?為什么還能強轉(zhuǎn)成IPackageManager
打印pm的className
```
System.out.println("pm.getName:" +pm.getClass().getName())
```
得出的結(jié)果:
```
pm.getName:com.sun.proxy.$Proxy0
```
也就是pm對象是com.sun.proxy.$Proxy0這個類new出的對象。這個類是剛剛Proxy.newProxyInstance自動生成的class
那這個class里面寫的是什么呢?
查看源碼:Proxy.java
```
/**
? ? * 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
? ? ? ? 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);
? ? ? ? ? ? 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());
? ? ? ? ? ? }
? ? ? ? }
? ? }
```
通過ProxyGenerator 生成了這個class。
查看ProxyGenerator源碼:
```
/**
? ? * Generate a proxy class given a name and a list of proxy interfaces.
? ? *
? ? * @param name? ? ? ? the class name of the proxy class
? ? * @param interfaces? proxy interfaces
? ? * @param accessFlags access flags of the proxy class
? ? */
? ? public static byte[] generateProxyClass(final String name,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class<?>[] interfaces,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int accessFlags)
? ? {
? ? ? ? ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
? ? ? ? final byte[] classFile = gen.generateClassFile();
? ? ? ? if (saveGeneratedFiles) {
? ? ? ? ? ? java.security.AccessController.doPrivileged(
? ? ? ? ? ? new java.security.PrivilegedAction<Void>() {
? ? ? ? ? ? ? ? public Void run() {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? int i = name.lastIndexOf('.');
? ? ? ? ? ? ? ? ? ? ? ? Path path;
? ? ? ? ? ? ? ? ? ? ? ? if (i > 0) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
? ? ? ? ? ? ? ? ? ? ? ? ? ? Files.createDirectories(dir);
? ? ? ? ? ? ? ? ? ? ? ? ? ? path = dir.resolve(name.substring(i+1, name.length()) + ".class");
? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? path = Paths.get(name + ".class");
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? Files.write(path, classFile);
? ? ? ? ? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? ? ? throw new InternalError(
? ? ? ? ? ? ? ? ? ? ? ? ? ? "I/O exception saving generated file: " + e);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? return classFile;
? ? }
```
發(fā)現(xiàn) saveGeneratedFiles 為true報錯生成的class的源碼。
這個saveGeneratedFiles 怎么賦值呢?
```
/** debugging flag for saving generated class files */
? ? private final static boolean saveGeneratedFiles =
? ? ? ? java.security.AccessController.doPrivileged(
? ? ? ? ? ? new GetBooleanAction(
? ? ? ? ? ? ? ? "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
```
也就是把sun.misc.ProxyGenerator.saveGeneratedFiles 改成true就可以輸出結(jié)果了。
```
? ? ? ? // 從源碼中得知,設(shè)置這個值,可以把生成的代理類,輸出出來。? ? ?
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
```
注意,需要再工程根目錄下,增加 com/sun/proxy目錄,否則會報錯如下:
```
Exception in thread "main" java.lang.InternalError: I/O exception saving generated file: java.io.FileNotFoundException : com\sun\proxy\$Proxy0.class (系統(tǒng)找不到指定的路徑。)
? ? at sun.misc.ProxyGenerator$1.run(ProxyGenerator.java:336 )
? ? at sun.misc.ProxyGenerator$1.run(ProxyGenerator.java:327 )
? ? at java.security.AccessController.doPrivileged(Native Method)
? ? at sun.misc.ProxyGenerator.generateProxyClass(ProxyGenerator.java:326)
? ? at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:672)
? ? at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:592)
? ? at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:244)
? ? at java.lang.reflect.WeakCache.get(WeakCache.java:141 )
? ? at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:455 )
? ? at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:738)
? ? at com.czq.proxy.Test.main( Test.java:18)
```
把proxy0輸出的結(jié)果如下:
反編譯看看proxy0是內(nèi)容是啥,有什么秘密
```
package com.sun.proxy;
import com.czq.proxy.IPackageManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
? implements IPackageManager
{
? private static Method m3; // 生成對應(yīng)的方法對象
? private static Method m1;
? private static Method m0;
? private static Method m2;
// proxy0 繼承Proxy,實現(xiàn)IPackageManager 接口,需要傳入 InvocationHandler,初始化對應(yīng)的h對象。
// 我們的h對象就是PackageManagerWoker,所以我們會調(diào)用到PackageManagerWoker的 invoke方法。
// 所以是proxy0,調(diào)用InvocationHandler的 invoke 方法,傳入對應(yīng)的方法。InvocationHandler 放射調(diào)用對應(yīng)的tagret中的方法。
? public $Proxy0(InvocationHandler paramInvocationHandler)
? ? throws
? {
? ? super(paramInvocationHandler);
? }
? public final String getPackageInfo()
? ? throws
? {
? ? try
? ? {
? ? ? return (String)this.h.invoke(this, m3, null);
? ? }
? ? catch (RuntimeException localRuntimeException)
? ? {
? ? ? throw localRuntimeException;
? ? }
? ? catch (Throwable localThrowable)
? ? {
? ? }
? ? throw new UndeclaredThrowableException(localThrowable);
? }
? public final boolean equals(Object paramObject)
? ? throws
? {
? ? try
? ? {
? ? ? return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
? ? }
? ? catch (RuntimeException localRuntimeException)
? ? {
? ? ? throw localRuntimeException;
? ? }
? ? catch (Throwable localThrowable)
? ? {
? ? }
? ? throw new UndeclaredThrowableException(localThrowable);
? }
? public final int hashCode()
? ? throws
? {
? ? try
? ? {
? ? ? return ((Integer)this.h.invoke(this, m0, null)).intValue();
? ? }
? ? catch (RuntimeException localRuntimeException)
? ? {
? ? ? throw localRuntimeException;
? ? }
? ? catch (Throwable localThrowable)
? ? {
? ? }
? ? throw new UndeclaredThrowableException(localThrowable);
? }
? public final String toString()
? ? throws
? {
? ? try
? ? {
? ? ? return (String)this.h.invoke(this, m2, null);
? ? }
? ? catch (RuntimeException localRuntimeException)
? ? {
? ? ? throw localRuntimeException;
? ? }
? ? catch (Throwable localThrowable)
? ? {
? ? }
? ? throw new UndeclaredThrowableException(localThrowable);
? }
? static
? {
? ? try
? ? {
? ? // 把各個方法,對應(yīng)到成員變量上
? ? ? m3 = Class.forName("com.czq.proxy.IPackageManager").getMethod("getPackageInfo", new Class[0]);
? ? ? 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]);
? ? ? 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é)論如下:
1. proxy0 繼承Proxy,實現(xiàn)IPackageManager 接口,需要傳入 InvocationHandler,初始化對應(yīng)的h對象。
2. 我們的h對象就是PackageManagerWoker,所以我們會調(diào)用到PackageManagerWoker的 invoke方法。
3. 所以是proxy0,調(diào)用InvocationHandler的 invoke 方法,傳入對應(yīng)的方法。InvocationHandler 放射調(diào)用對應(yīng)的tagret中的方法。套了2層
整體類圖如下
