JDK動(dòng)態(tài)代理詳解
java動(dòng)態(tài)代理類(lèi)
Java動(dòng)態(tài)代理類(lèi)位于java.lang.reflect包下譬涡,一般主要涉及到以下兩個(gè)類(lèi):
InvocationHandler
該類(lèi)是個(gè)接口荡澎,僅定義了一個(gè)方法
public interface InvocationHandler {
/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return the value to return from the method invocation on the
* proxy instance. If the declared return type of the interface
* method is a primitive type, then the value returned by
* this method must be an instance of the corresponding primitive
* wrapper class; otherwise, it must be a type assignable to the
* declared return type. If the value returned by this method is
* {@code null} and the interface method's return type is
* primitive, then a {@code NullPointerException} will be
* thrown by the method invocation on the proxy instance. If the
* value returned by this method is otherwise not compatible with
* the interface method's declared return type as described above,
* a {@code ClassCastException} will be thrown by the method
* invocation on the proxy instance.
*
* @throws Throwable the exception to throw from the method
* invocation on the proxy instance. The exception's type must be
* assignable either to any of the exception types declared in the
* {@code throws} clause of the interface method or to the
* unchecked exception types {@code java.lang.RuntimeException}
* or {@code java.lang.Error}. If a checked exception is
* thrown by this method that is not assignable to any of the
* exception types declared in the {@code throws} clause of
* the interface method, then an
* {@link UndeclaredThrowableException} containing the
* exception that was thrown by this method will be thrown by the
* method invocation on the proxy instance.
*
* @see UndeclaredThrowableException
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
在實(shí)際使用時(shí)罪帖,第一個(gè)參數(shù)obj一般是指代理類(lèi)精盅,method是被代理的方法,args為該方法的參數(shù)數(shù)組。第一個(gè)參數(shù)基本上不會(huì)用到柳爽。
Proxy
該類(lèi)即為動(dòng)態(tài)代理類(lèi),其中主要包含以下內(nèi)容
- protected Proxy(InvocationHandler h):構(gòu)造函數(shù)碱屁,用于給內(nèi)部的h賦值
- static Class getProxyClass (ClassLoaderloader, Class[] interfaces):獲得一個(gè)代理類(lèi)磷脯,其中l(wèi)oader是類(lèi)裝載器,interfaces是真實(shí)類(lèi)所擁有的全部接口的數(shù)組
- static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理類(lèi)的一個(gè)實(shí)例娩脾,返回后的代理類(lèi)可以當(dāng)作被代理類(lèi)使用(可使用被代理類(lèi)的在Subject接口中聲明過(guò)的方法)
在使用動(dòng)態(tài)代理類(lèi)時(shí)赵誓,我們必須實(shí)現(xiàn)InvocationHandler接口
動(dòng)態(tài)代理步驟
- 創(chuàng)建一個(gè)實(shí)現(xiàn)接口InvocationHandler的類(lèi),它必須實(shí)現(xiàn)invoke方法
- 創(chuàng)建被代理的類(lèi)以及接口
- 通過(guò)Proxy的靜態(tài)方法
? newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)創(chuàng)建一個(gè)代理
- 通過(guò)代理調(diào)用方法
使用
- 需要?jiǎng)討B(tài)代理的接口
/**
* @author Date: 2017/5/16 Time: 10:30.
*/
public interface Student {
void study();
}
- 需要代理的實(shí)際對(duì)象
/**
* @author Date: 2017/5/16 Time: 10:39.
*/
public class GoodStudent implements Student {
public void study() {
System.out.println("study hard");
}
}
- 調(diào)用處理器實(shí)現(xiàn)類(lèi)
/**
* @author Date: 2017/5/16 Time: 10:37.
*/
public class ProxyHandler implements InvocationHandler {
private Object student;
public ProxyHandler(Object student) {
this.student = student;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("hello before");
Object result = method.invoke(student,args);
System.out.println("bye after");
return result;
}
}
該調(diào)用處理器實(shí)現(xiàn)類(lèi)構(gòu)造函數(shù)接收一個(gè)Object對(duì)象柿赊。在invoke方法中method.invoke(student,args)是對(duì)被代理對(duì)象方法的調(diào)用俩功,在該調(diào)用前后分別輸出了語(yǔ)句。
- 測(cè)試
/**
* @author Date: 2017/5/16 Time: 10:31.
*/
public class ProxyTest {
public static void main(String[] args) {
GoodStudent goodStudent = new GoodStudent();
Student proxyStudent =
(Student) Proxy.newProxyInstance(Student.class.getClassLoader(),
new Class[] {Student.class}, new ProxyHandler(goodStudent));
proxyStudent.study();
}
}
輸出
hello before
study hard
bye after
可以看到study hard是由goodStudy對(duì)象的study方法輸出的碰声,而前后的輸出則是調(diào)用處理器實(shí)現(xiàn)類(lèi)中增加的绑雄。
原理
從代碼中可以看出關(guān)鍵點(diǎn)在于以下這段代碼
Student proxyStudent =
(Student) Proxy.newProxyInstance(Student.class.getClassLoader(),
new Class[] {Student.class}, new ProxyHandler(goodStudent));
來(lái)看看newProxyInstance的源碼
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.
*/
//重點(diǎn)是cl怎么來(lái)的
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//cons是cl類(lèi)的構(gòu)造函數(shù)
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//最后返回的實(shí)例是由cons構(gòu)造函數(shù)構(gòu)造出來(lái)的
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);
}
}
可以看到該方法返回的實(shí)例是cl的構(gòu)造函數(shù)構(gòu)造出來(lái)的,那我們重點(diǎn)看看cl是怎么來(lái)的奥邮。
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);
}
可以看到這里對(duì)傳入的interfaces數(shù)組長(zhǎng)度有限制,不能超過(guò)65535.最后的數(shù)據(jù)都是從proxyClassCache緩存中獲取的罗珍,來(lái)看看這個(gè)緩存的定義洽腺。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
緩存中的對(duì)象則是由ProxyClassFactory構(gòu)造的。
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
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.
*/
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());
}
}
}
重點(diǎn)在于這一句
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
這一句生成了代理類(lèi)的字節(jié)碼覆旱。接下來(lái)我們著重分析該方法做了什么
generateProxyClass
我們可以將ProxyGenerator為我們生成的字節(jié)碼保存在磁盤(pán)中蘸朋,然后通過(guò)反編譯看看其實(shí)現(xiàn)。代碼如下:
/**
* @author Date: 2017/5/16 Time: 10:31.
*/
public class ProxyTest {
public static void main(String[] args) {
createProxyClassFile();
}
public static void createProxyClassFile() {
String name = "ProxyStudent";
byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] {Student.class});
try {
FileOutputStream out = new FileOutputStream(name + ".class");
out.write(data);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
上述代碼會(huì)替我們生成一個(gè)Student的代理類(lèi)扣唱,并保存在ProxyStudent.class文件中藕坯,類(lèi)名為ProxyStudent团南。
來(lái)看看反編譯后的結(jié)果
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public final class ProxyStudent extends Proxy implements Student {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public ProxyStudent(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void study() throws {
try {
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)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("com.test.Student").getMethod("study", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到該類(lèi)繼承了Proxy類(lèi),并實(shí)現(xiàn)了Student接口炼彪。這就是為什么我們能將其實(shí)例轉(zhuǎn)化為代理接口對(duì)象吐根。該類(lèi)包含了4個(gè)Method對(duì)象,并在靜態(tài)代碼快中初始化了這四個(gè)對(duì)象辐马。其中三個(gè)是繼承自O(shè)bject的方法:
- m1:equals
- m2:toString
- m0:hashCode
m3才是我們自定義接口中的方法拷橘。
該類(lèi)的構(gòu)造函數(shù)接收一個(gè)InvocationHandler對(duì)象,并將其傳遞給了父類(lèi)Proxy喜爷。而該類(lèi)中所有方法的調(diào)用都直接扔給了Proxy類(lèi)中的InvocationHandler對(duì)象∪叽現(xiàn)在可以知道我們實(shí)現(xiàn)的InvocationHandler接口類(lèi)的實(shí)例的作用了。
流程
梳理下流程:
- 利用ProxyGenerator.generateProxyClass為被代理的類(lèi)(接口)生成代理類(lèi)(Proxy)
- 將實(shí)現(xiàn)的InvocationHandler對(duì)象作為代理類(lèi)的構(gòu)造函數(shù)參數(shù)傳遞進(jìn)去檩帐,得到代理類(lèi)實(shí)例
- 使用代理類(lèi)實(shí)例完成對(duì)被代理對(duì)象的代理
Mybatis中的應(yīng)用
mybatis中mapper的實(shí)現(xiàn)就利用了jdk動(dòng)態(tài)代理术幔。
核心類(lèi)
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
所有對(duì)Mapper的方法調(diào)用最終都代理給了MapperProxy。該類(lèi)的核心代碼如下:
public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
}
注意到該類(lèi)正是實(shí)現(xiàn)了InvocationHandler接口湃密。而自定義的方法最終都由mapperMethod來(lái)執(zhí)行了诅挑,接著mapperMethod又交給SqlSession來(lái)執(zhí)行了,細(xì)節(jié)請(qǐng)自行閱讀Mybatis源碼勾缭。