0. 下了有一个月的雨,这对鼻炎来说来吗?不好
其实这也算6月份的博客,之前一直疏于整理
- 本文仅关注jdk代理所实现的spring.aop下,两者的关系
- 完整的aop源码走读请移步相关 spring.aop 的其他随笔
1. 反编译追踪源码
1.1 jdk代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import com.weng.cloud.sample.aop.dto.Order;
import com.weng.cloud.sample.aop.service.OrderService;
import java.io.Serializable;
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 OrderService, Serializable {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// 接口实现类
public final Order queryOrder(String var1) throws {
try {
// step into super class(invocationHandler) ...
return (Order)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// 接口实现类
public final Order createOrder(String var1, String var2) throws {
try {
return (Order)super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
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);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.weng.cloud.sample.aop.service.OrderService").getMethod("queryOrder", Class.forName("java.lang.String"));
m3 = Class.forName("com.weng.cloud.sample.aop.service.OrderService").getMethod("createOrder", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
1.2 java.lang.reflect.InvocationHandler.invoke() spring.aop组装 jdk代理所需的参数
/**
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取增强逻辑的advices
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// proxy:方法外部 Proxy.newInstance() 产出的代理实例
// target:targetSource中保存的目标实例(在aop调用过程中维护Class实例)
// method:java.lang.reflect.Method
// args:方法参数
// targetClass:target.getClass()
// chain:增强逻辑advices
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// step into ...
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1.3 spring.aop.MethodInvocation.proceed() 递归调用 advices
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
到这基本结束了,下面内容属于加餐选项
2. cglib代理类反编译源码
其实cglib除了生成代理类的字节码以外,还生成了 Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$xxxx 的字节码。初略的看了一下,果不其然,跟jdk代理一样,使用了 WeakCache 一类的弱缓存技术,只不过是cglib自己实现的。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.weng.cloud.sample.ctx;
import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
public class SingleService$$EnhancerBySpringCGLIB$$cc775f74 extends SingleService implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private NoOp CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private MethodInterceptor CGLIB$CALLBACK_2;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$protoService$0$Method;
private static final MethodProxy CGLIB$protoService$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
static void CGLIB$STATICHOOK3() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.weng.cloud.sample.ctx.SingleService$$EnhancerBySpringCGLIB$$cc775f74");
Class var1;
CGLIB$protoService$0$Method = ReflectUtils.findMethods(new String[]{"protoService", "()Lcom/weng/cloud/sample/ctx/ProtoService;"}, (var1 = Class.forName("com.weng.cloud.sample.ctx.SingleService")).getDeclaredMethods())[0];
CGLIB$protoService$0$Proxy = MethodProxy.create(var1, var0, "()Lcom/weng/cloud/sample/ctx/ProtoService;", "protoService", "CGLIB$protoService$0");
}
final ProtoService CGLIB$protoService$0() {
return super.protoService();
}
// 被增强的方法
public final ProtoService protoService() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
// 调用增强逻辑 methodInterceptor.intercept()
return var10000 != null ? (ProtoService)var10000.intercept(this, CGLIB$protoService$0$Method, CGLIB$emptyArgs, CGLIB$protoService$0$Proxy) : super.protoService();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case 1187820471:
if (var10000.equals("protoService()Lcom/weng/cloud/sample/ctx/ProtoService;")) {
return CGLIB$protoService$0$Proxy;
}
}
return null;
}
// 构造器
public SingleService$$EnhancerBySpringCGLIB$$cc775f74() {
// 初始化绑定关系(MethodInterceptor)
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
SingleService$$EnhancerBySpringCGLIB$$cc775f74 var1 = (SingleService$$EnhancerBySpringCGLIB$$cc775f74)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
Callback[] var10001 = (Callback[])var10000;
var1.CGLIB$CALLBACK_2 = (MethodInterceptor)((Callback[])var10000)[2];
var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
var1.CGLIB$CALLBACK_0 = (NoOp)var10001[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
SingleService$$EnhancerBySpringCGLIB$$cc775f74 var10000 = new SingleService$$EnhancerBySpringCGLIB$$cc775f74();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
throw new IllegalStateException("More than one callback object required");
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
SingleService$$EnhancerBySpringCGLIB$$cc775f74 var10000 = new SingleService$$EnhancerBySpringCGLIB$$cc775f74;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
Object var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
case 1:
var10000 = this.CGLIB$CALLBACK_1;
break;
case 2:
var10000 = this.CGLIB$CALLBACK_2;
break;
default:
var10000 = null;
}
return (Callback)var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (NoOp)var2;
break;
case 1:
this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;
break;
case 2:
this.CGLIB$CALLBACK_2 = (MethodInterceptor)var2;
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (NoOp)var1[0];
this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
this.CGLIB$CALLBACK_2 = (MethodInterceptor)var1[2];
}
static {
CGLIB$STATICHOOK3();
}
}
3. JOOR 封装jdk代理
简单带过一下,毕竟这个框架虽然好用,但并不受到广泛关注:
开源(目前在github维护)、轻量级(无第三方依赖)、支持链式调用 的 java反射库
3.1 先来个代理api的测试用例
@DisplayName("官方MD中的代理用例")
@Test
void t1() {
// 创建String的实例,同时作为 StringProxy的代理实例
String stringProxy = Reflect.onClass(String.class.getName())
.create(" hello world ")
// step into ...
// jdk代理api
.as(StringProxy.class)
.substring(6);
System.err.println(stringProxy);
}
3.2 源码
/**
* Create a proxy for the wrapped object allowing to typesafely invoke methods
* on it using a custom interface.
*
* @param proxyType The interface type that is implemented by the proxy
* @return A proxy for the wrapped object
*/
public <P> P as(Class<P> proxyType) {
// step into ...
return as(proxyType, new Class[0]);
}
/**
* Create a proxy for the wrapped object allowing to typesafely invoke
* methods on it using a custom interface.
*
* @param proxyType The interface type that is implemented by the proxy
* @param additionalInterfaces Additional interfaces that are implemented by
* the proxy
* @return A proxy for the wrapped object
*/
@SuppressWarnings("unchecked")
public <P> P as(final Class<P> proxyType, final Class<?>... additionalInterfaces) {
final boolean isMap = (object instanceof Map);
final InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
// Actual method name matches always come first
try {
return on(type, object).call(name, args).get();
}
// [#14] Emulate POJO behaviour on wrapped map objects
catch (ReflectException e) {
if (isMap) {
Map<String, Object> map = (Map<String, Object>) object;
int length = (args == null ? 0 : args.length);
if (length == 0 && name.startsWith("get")) {
return map.get(property(name.substring(3)));
}
else if (length == 0 && name.startsWith("is")) {
return map.get(property(name.substring(2)));
}
else if (length == 1 && name.startsWith("set")) {
map.put(property(name.substring(3)), args[0]);
return null;
}
}
if (method.isDefault()) {
Lookup proxyLookup = null;
// Java 9 version
if (CACHED_LOOKUP_CONSTRUCTOR == null) {
// Java 9 version for Java 8 distribution (jOOQ Open Source Edition)
if (proxyLookup == null)
proxyLookup = onClass(MethodHandles.class)
.call("privateLookupIn", proxyType, MethodHandles.lookup())
.call("in", proxyType)
.<Lookup> get();
}
// Java 8 version
else
proxyLookup = CACHED_LOOKUP_CONSTRUCTOR.newInstance(proxyType);
return proxyLookup.unreflectSpecial(method, proxyType)
.bindTo(proxy)
.invokeWithArguments(args);
}
throw e;
}
}
};
Class<?>[] interfaces = new Class[1 + additionalInterfaces.length];
interfaces[0] = proxyType;
System.arraycopy(additionalInterfaces, 0, interfaces, 1, additionalInterfaces.length);
// 原汁原味
return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), interfaces, handler);
}