1.重要參數:
在java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現我們動態代理所必須用到的。
(1)InvocationHandler
每一個動態代理類都必須要實現InvocationHandler這個接口,並且每個代理類的實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的 invoke 方法來進行調用。我們來看看InvocationHandler這個接口的唯一一個方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我們所代理的那個真實對象
method: 指代的是我們所要調用真實對象的某個方法的Method對象
args: 指代的是調用真實對象某個方法時接受的參數
(2)Proxy
Proxy這個類的作用就是用來動態創建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
interfaces: 一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什麼接口
h: 一個InvocationHandler對象,表示的是會關聯到哪一個InvocationHandler對象上
說白了就是用loader來加載代理對象的interfaces並且綁定到h上供代理對象調用
2.示例代碼:
public interface Subject {
public void rent();
public void hello(String str);
}
定義了一個類來實現這個接口,這個類就是我們的真實對象
public class RealSubject implements Subject {
@Override
public void rent() {
System.out.println("I want to rent my house");
}
@Override
public void hello(String str) {
System.out.println("hello: " + str);
}
}
定義一個動態代理類了,前面說個,每一個動態代理類都必須要實現 InvocationHandler 這個接口
public class DynamicProxy implements InvocationHandler {
// 這個就是我們要代理的真實對象
private Object subject;
// 構造方法,給我們要代理的真實對象賦初值
public DynamicProxy(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
//在代理真實對象前我們可以添加一些自己的操作
//System.out.println("before rent house");
//當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用
method.invoke(subject, args);
//在代理真實對象後我們也可以添加一些自己的操作
//System.out.println("after rent house");
return null;
}
}
測試:
public static void main(String[] args) {
// 我們要代理的真實對象
Subject realSubject = new RealSubject();
// 我們要代理哪個真實對象,就將該對象傳進去,最後是通過該真實對象來調用其方法的
InvocationHandler handler = new DynamicProxy(realSubject);
/*
* 通過Proxy的newProxyInstance方法來創建我們的代理對象,我們來看看其三個參數 第一個參數
* handler.getClass().getClassLoader()
* ,我們這裏使用handler這個類的ClassLoader對象來加載我們的代理對象
* 第二個參數realSubject.getClass().getInterfaces(),我們這裏爲代理對象提供的接口是真實對象所實行的接口
* ,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了 第三個參數handler, 我們這裏將這個代理對象關聯到了上方的
* InvocationHandler 這個對象上
*/
Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
// 替代靜態代理的new
subject.rent();
subject.hello("world");
}
輸出:
I want to rent my house
hello: world
3.源碼跟蹤:
public class Proxy implements java.io.Serializable {
/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
//******************返回proxyClassCache.get(loader, interfaces);有必要研究一下這個proxyClassCache如何初始化的
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);//獲得動態代理的構造函數
final InvocationHandler ih = h;
return cons.newInstance(new Object[]{h});//生成實例
} catch (Exception e) {
}
}
}
搜遍整個代碼會發現proxyClassCache好像並沒有初始化。但是getProxyClass0裏面有段提示
// 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
也就是會通過KeyFactory生成一個key(這個key就是interface的hashCode),ProxyClassFactory生成一個代理類
ProxyClassFactory繼承自BiFunction接口,重點關注apply函數
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) {
}
......
}
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");
}
}
}
/*
* 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, accessFlags);//********************************
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
}
}
}
接下來看看generateProxyClass
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 More ...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;
}
private byte[] generateClassFile() {
/* ============================================================
* Step 1: Assemble ProxyMethod objects for all methods to
* generate proxy dispatching code for.
*/
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);//------------------------------這裏會調用invoke的接口方法
}
}
......
return bout.toByteArray();
}