第一部分:JDK8動態代理基本實現
1,先定義一個接口
public interface UserService {
void work(String workContent);
}
2,再定義一個接口實現類
public class StudentService implements UserService {
@Override
public void work(String workContent) {
System.out.println("StudentService work:" + workContent);
}
}
3,定義最關鍵的InvocationHandler實現類
public class UserProxyHandler implements InvocationHandler {
UserService realService;
UserService proxyInstance;
public UserProxyHandler(UserService userService) {
realService = userService;
//關鍵點1:代理實例生成
proxyInstance = (UserService) Proxy.newProxyInstance(getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
}
public UserService getRealService() {
return realService;
}
public UserService getProxyInstance() {
return proxyInstance;
}
// 關鍵點2:代理實例的接口方法會調用InvocationHandler的invoke方法
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("UserProxyHandler before");
// 代理實現的地方
Object result = method.invoke(realService, objects);
System.out.println("UserProxyHandler after");
return result;
}
}
4,調用代理類,觀察代理過程
StudentService studentService = new StudentService();
UserProxyHandler userProxyHandler = new UserProxyHandler(studentService);
userProxyHandler.getProxyInstance().work("proxy go school");
輸出結果:
結果分析
整個過程結果都看到,我們明明調用的是代理對象的work方法,但最終還是進入了UserProxyHandler的invoke方法,並通過代理層,調用了真實類的StudentService的work方法。
但是我們還是不清楚JDK到底是如何實現這一步的,其實重點就是2個問題:
- 代理對象是如何產生的
- InvocationHandler的invoke方法具體的怎麼調用的
那就老老實實看源碼
第二部分:JDK8動態代理原理解析
一,代理對象的產生過程
這部分基本就要看JDK8的源碼了,直接IDEA上面一步步,看源碼的實現過程,這裏只分析重點代碼。
Proxy.newProxyInstance方法
將該方法簡化後,其實就做了三部:
- 得到代理類的Class對象
- 獲得該Class對象的構造函數反射
- 調用構造函數反射生成對象
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,,InvocationHandler h) {
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
}
很明顯,其中重要的就是第一步,jdk如何得到代理類的Class對象,
該Class對象的生成過程getProxyClass0()。
getProxyClass0()
然而,這個方法內部很簡單。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache.get()
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
該方法主要是做了一層內存緩存。具體的Class生成過程其實在ProxyClassFactory裏面
緩存過程分析:
get方法首先創建一個valuesMap,獲取subKey,裏面比較重要的就是subKeyFactory.apply(key,parameter),這個方法會幫我們生成代理類的subKey,之後會建立一個Factory,當使用Factory.get的時候,回去調用valueFactory.apply()
valueFactory即構造函數裏面的ProxyClassFactory,便是真正生成代理類的時候。
緩存的思考:
由於第一次的時候需要動態的去創建字節碼,然後進行加載,初始化,因此效率和直接new對象相比會比較低下。 這也是使用緩存的原因。雖然有緩存,但是由於使用了WeakReference,GC後有可能會被回收,那麼就得重新加載,一定程度上會降低效率,所以一般情況下,我們儘量避免這種動態生成類的方式,而是用在編譯時生成類的方式取代,這便是APT技術的精髓。
public V get(K key, P parameter) {
Object cacheKey = CacheKey.valueOf(key, refQueue);
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()
這裏面主要五點,
1,利用Class.forName複製一份接口參數傳入的接口Class對象
2,拼接Proxy的類名形爲: xxx$Proxy0
3,代理類的accessFlags
4,ProxyGenerator.generateProxyClass()獲得Class字節碼
5,ProxyGenerator.defineClass0() 通過native調用加載字節碼,獲取Java層Proxy的Class對象
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
interfaceClass = Class.forName(intf.getName(), false, loader);
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
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);
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
至此,代理類的對象生成過程就徹底搞清楚了
二,InvocationHandler的invoke調用時機
我們大膽猜測,具體過程肯定都在ProxyGenerator.generateProxyClass()的生成過程中。
也就是裏面的generateClassFile()方法中,此處代碼沒有註釋,只能猜測着看
直接搜索InvocationHandler,很明顯發現:
1, generateConstructor 生成了注入InvocationHandler的代理類構造函數
private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
DataOutputStream var2 = new DataOutputStream(var1.code);
this.code_aload(0, var2);
this.code_aload(1, var2);
var2.writeByte(183);
var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
var2.writeByte(177);
var1.maxStack = 10;
var1.maxLocals = 2;
var1.declaredExceptions = new short[0];
return var1;
}
2,ProxyMethod.generateMethod 生成了調用InvocationHandler.invoke的代理接口方法(這裏只展示部分代碼)
private ProxyGenerator.MethodInfo generateMethod() throws IOException {
String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);
int[] var3 = new int[this.parameterTypes.length];
int var4 = 1;
for(int var5 = 0; var5 < var3.length; ++var5) {
var3[var5] = var4;
var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]);
}
byte var7 = 0;
DataOutputStream var9 = new DataOutputStream(var2.code);
ProxyGenerator.this.code_aload(0, var9);
var9.writeByte(180);
var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
ProxyGenerator.this.code_aload(0, var9);
var9.writeByte(178);
var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
if (this.parameterTypes.length > 0) {
ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
var9.writeByte(189);
var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));
for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
var9.writeByte(89);
ProxyGenerator.this.code_ipush(var10, var9);
this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
var9.writeByte(83);
}
} else {
var9.writeByte(1);
}
var9.writeByte(185);
var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));
var9.writeByte(4);
var9.writeByte(0);
}
我們可以調用ProxyGenerator.generateProxyClass來看一下這個生成的類,把它寫到文件裏,然後打開驗證一下,關鍵方法如下所示:
public final void work(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
至此,謎底全部解開了!!!