Spring-framework5.0.2 源码阅读笔记 - AOP切面(代码织入阶段)
Spring AOP 代码织入阶段
注意: 本片博客所展示的代码中,删除了对核心流程以外的代码,为了不影响观看,所以只保留了最核心的代码
spring 初始化时序图 (免费克隆)
Spring-framework 5.0.2 中文注释源码下载
闲聊
AOP
主要是分为两个部分,第一部分对需要代理的bean
《创建代理对象》,存入IOC
容器,则这第二部分就是使用AOP
阶段了。根据我所提供的时序图中,AOP
部分可以看出,以JDK
为例,一切动态代理的入口都将会是InvocationHandler#invoke()
方法,那么在哪里实现了InvocationHandler
接口呢!回想一下,貌似JdkDynamicAopProxy
类就实现了InvocationHandler
接口哇,那么为了认证这么一个*”好像“*,就直接进入主题呗
1. 以JDK为例,织入InvocationHandler#invoke()
进入
JdkDynamicAopProxy
类中,找到invoke()
,源码如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//equals()方法,具目标对象未实现此方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
//hashCode()方法,具目标对象未实现此方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//获得目标对象的类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//获取可以应用到此方法上的Interceptor列表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//创建MethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, 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())) {
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);
}
}
}
根据上面的代码和注释,可以简单的看出大致逻辑:
首先获取应用到此方法上的Interceptor
列表,如果该方法上没有任何通知链,那么直接调用该方法做反射执行,如果有响应的通知存在,那么直接创建MethodInvocation
,调用其proceed()
,其内部依然是执行了JoinPoint
2. 拦截器链的获取和执行
在这一步中,最为关键的就是获取到
interceptorChian
,那么它是如何获取,又是如何执行的,下面开始一一解读:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 通过方法缓存获取
List<Object> cached = this.methodCache.get(cacheKey);
// 如果没有获取到,则尝试使用 AdvisorChainFactory的子类DefaultAdvisorChainFactory 进行获取
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
下面进入
DefaultAdvisorChainFactory
查看getInterceptorsAndDynamicInterceptionAdvice()
/**
* 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor,
* 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断
* 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.
*/
@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.
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
//查看是否包含IntroductionAdvisor
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
//这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//这个地方这两个方法的位置可以互换下
//将Advisor转化成Interceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//检查当前advisor的pointcut是否可以匹配当前方法
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
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));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
上面的大致逻辑:
- 拿到所有的
Advisor
,判断,如果类型属于PointcutAdvisor
(切入点)那么就将所有的PointcutAdvisor
,转换成MthodInterceptor
数组,遍历添加到chain
中,- 如果
Advisor
是属于IntroductionAdvisor(引入)
类型,那么就将Advisor
转换成Interceptor
数组,存入到chain
中- 如果既不是
PointcutAdvisor
,也不是IntroductionAdvisor
,那直接转换成Interceptor
数组,加入到chain
中
至此,获取
InterceptorChain
的工作就完毕了
3. 获取到interceptorChain不为空的情况
接下来就是使用这个
chain
了,回到JdkDynamicAopProxy#invoke()
中,如果chain
不为空的时候,则看一下代码:
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// is not empty
else {
//创建 ReflectiveMethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 通过得到的拦截器列表,执行各个拦截点
retVal = invocation.proceed();
}
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//如果Interceptor执行完了,则执行joinPoint
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果要动态匹配joinPoint
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//动态匹配:运行时参数是否满足匹配条件
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor, 使用递归方式进行调用,但是不属于同一个拦截器
return proceed();
}
}
else {
//执行当前Intercetpor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
通过以上代码:
- 先获取到当前的拦截器,如果该拦截器的类型是动态匹配的类型,那么进入动态匹配类型
1.1.如果参数满足条件,那么则直接运行拦截器
1.2.如果不满足,则使用递归,调用下一个拦截器,这里的递归虽然运行的方法是一样的,但是运行的效果有可能完全不相同。- 如果不是动态匹配的拦截器,那么直接执行当前的拦截器
4. 总结
通过以上一顿操作后,
AOP
执行其实就是在目标方法被调用的时候,执行代理的invoke()
,使用预先加载好的拦截器来匹配目标方法是否拥有被拦截的权限。如果有,则将执行配置的切入点,如果没有,则反射调用目标方法。奥里给!!!
接下来最后一篇
MVC
的调用阶段文章会发布,敬请期待!
本文地址:https://blog.csdn.net/qq_38800175/article/details/109530246
上一篇: springboot + vue上传图片在服务器并实现在线预览
下一篇: ThreadLocal