Spring AOP source directory
Spring AOP Source 01: Jdk dynamic proxy for the underlying source
Spring AOP Source 02: the ProxyFactory
Spring AOP Source 03: JdkDynamicAopProxy
Spring AOP Source 04: MethodInvocation call interceptor
Spring AOP Source 05: The DefaultAdvisorAutoProxyCreator
the Spring finale final exam question: When Spring AOP met circular dependencies
Notes git source address: https: //github.com/chaitou/spring-framework-master.git
Foreword
Below, The second binding Spring AOP the ProxyFactory core source , there Spring AOP dynamic proxy generation mode 2, when the proxy object implements the interface and is not forced to use the configuration cglib代理
is used when JdkDynamicAopProxy
generating agent. Conversely used CglibAopProxy
to generate the proxy. In the first chapter we dynamic proxy for the underlying source Jdk known, Jdk dynamic agent by getProxy
simultaneously generating a proxy, $proxy
the proxy object when calling the method, will callback invoke
method. So for JdkDynamicAopProxy
, the most important code is the analysis getProxy
and invoke
methods. As for the underlying source code generating agent, a first article has been introduced, no further explanation
Source code analysis
getProxy
The following code in the first chapter Jdk dynamic proxy for the underlying source code we wrote again manually, then go over here
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断接口是否又hashCode和equals方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK代理(classLoader, 接口, 当前JdkDynamicAopProxy对象:用于回调invoke和target对象方法)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
classLoader
: The current class loaderproxiedInterfaces
: The current array of interfaces implemented by the proxy classthis
: The self-generated object to the proxy class, the properties of the agent as h, h property will be used to trigger the callback methodh.invoke
method for enhanced
invoke
In the beginning invoke
before the first fix a target, in order to seize the trunk, only interested in the topic 普通增强
, 引介增强
and so will skip the other a separate chapter explain, so encounter 引介增强
such as being the first can not tangle
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 {
// equals方法处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashCode处理
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);
}
// 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;
// 目标对象内部调用是无法实现增强的,如果exposeProxy设置为true,需要暴露代理
// ThreadLocal<Object> currentProxy
// 对象是ThreadLocal,在finally后会清除currentProxy
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来自对象池,所以在创建代理前调用get获取target
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 1. 获取拦截器链
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 {
// We need to create a method invocation...
// 2. 将拦截器统一封装成ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 3. 执行拦截器链
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,释放target资源池由子类实现
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1. Obtain interceptor chain
This method takes all the current method
matching advice
(enhancement), the tracking getInterceptorsAndDynamicInterceptionAdvice
code is found to be used Spring AOP cache to improve performance, if the process has been acquired through the interceptor fetch buffer directly, or by advisorChainFactory
acquiring interceptor chain
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 从缓存中获取
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 获取拦截器链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 设置缓存
this.methodCache.put(cacheKey, cached);
}
return cached;
}
Continue with the getInterceptorsAndDynamicInterceptionAdvice
method
// DefaultAdvisorChainFactory.java
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 循环所有切面
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校验当前Advisor是否适用于当前对象
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 校验Advisor是否应用到当前方法上
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 匹配成功
if (match) {
// 从advisor中获取拦截器数组
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
// 添加动态拦截器
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
// 添加普通拦截器
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 引介增强
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 其他类型的advisor
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
...
}
Cut-away 引介增强
, 动态增强
we care about 普通拦截器
. The entire code is quite clear thinking, get all the Advisor
(cut) through pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)
matches Advisor check the current proxy object, and then by pointcutAdvisor.getPointcut().getMethodMatcher()
verifying that matches the current call method
. If the check then extracting advisor
the interceptors
interceptor, added to interceptorList
the
2. interceptor encapsulated into ReflectiveMethodInvocation
Call a constructor, focusing on the next call
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
3. Perform the interceptor chain
// 执行拦截器链
retVal = invocation.proceed();
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);
}
}
Similarly, we only care 普通拦截器
, but see 普通拦截器
only one line of code
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
This line of code can make interceptors in accordance with Before, After and even user-defined order Order were chained calls, this is amazing, right? The next section we will single out AspectJAfterAdvice
and MethodBeforeAdviceInterceptor
ordered interceptor called before the inquiry is how to enhance and method