Spring AOP的大致流程
我们在之前的2章中,知晓了Spring AOP
在BeanPostProcessor
的几个关键接口做了介入,分为几个关键点:
- 将切面类进行解析成
advisors
,其中包括解析XML
和被@Aspect
注解标注的Java切面类. - 在初始化Bean的阶段,将
advisors
对当前Bean
进行筛选,获取到当前Bean
匹配的advisors
. - 进行动态代理类的创建.
今天,我们就来看看动态代理类在Spring AOP中是怎样去创建出来的.
创建动态代理的入口:wrapIfNecessary
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的TargetSource被解析过了
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果Bean为advisedBeans,也不需要被代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// isInfrastructureClass和shouldSkip的作用:
// 识别切面类,加载切面类成advisors
// 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 返回匹配当前Bean的所有Advice、Advisor、Interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 下次代理的时候直接从缓存拿出判断,不需要重复代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
targetSourcedBeans
存储了用户自定义的targetSource,这部分的bean在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
中已经进行了createProxy
的处理,所以在自动化代理的环节中,要过滤掉这部分的bean.advisedBeans
存储了已经被Spring AOP处理过的bean,这部分的bean也是需要进行过滤的.- 进行
isInfrastructureClass
和shouldSkip
的处理,这两个方法在之前的文章已经做了详细的解析,它们的主要作用是:识别切面类、解析切面类。之所以再重复调用一次,是为了收尾的工作.getAdvicesAndAdvisorsForBean
获取当前bean匹配的advisors.- 将当前bean缓存到
advisedBeans
,创建动态代理-createProxy
,缓存proxyType
. 这里无论是否能获取到bean的advisors,都会做缓存到advisedBeans
的步骤.已确保不重复处理同一个bean.
创建动态代理:createProxy
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 如果beanFactory是ConfigurableListableBeanFactory的类型,暴露目标类
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建一个ProxyFactory,当前ProxyCreator在创建代理时,将需要用到的字段赋值到ProxyFactory中去
ProxyFactory proxyFactory = new ProxyFactory();
// 将当前的AnnotationAwareAspectJAutoProxyCreator对象的属性赋值给ProxyFactory对象
// 加载一些ProxyConfig
proxyFactory.copyFrom(this);
// 处理proxyTargetClass属性
// 如果希望使用CGLIB进行代理,配置proxyTargetClass为true
if (!proxyFactory.isProxyTargetClass()) {
// 检查相应BeanDefinition的“ preserveTargetClass”属性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 1. 有接口的,调用一次或者多次:proxyFactory.addInterface(ifc);
// 2. 没有接口的,调用: proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 这个方法主要是对前面传递进来的横切逻辑实例进行包装
// specificInterceptors中有Advice和Interceptor,它们都会被包装成Advisor
// 调用的先后顺序,通过方法中的applyCommonInterceptorsFirst参数进行设置
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 扩展实现,子类可以定制proxyFactory
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 设置preFiltered的属性值,默认为false.子类:AbstractAdvisorAutoProxyCreator修改为true
// preFiltered字段的意思是:是否为特定目标类筛选Advisor
// 该字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取所有的Advisors
// CglibAopProxy和JdkDynamicAopProxy都会调用此方法,然后递归执行所有的advisor
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
- 如果当前的beanFactory属于
ConfigurableListableBeanFactory
类型,给当前bean对应的BeanDefinition设置上属性"originalTargetClass"为targetClass.- 先new一个
ProxyFactory
实例,并根据AnnotationAwareAspectJAutoProxyCreator
的配置进行proxyTargetClass
、optimize
、exposeProxy
、frozen
、opaque
的属性设置.- Spring不仅提供了对所有bean生效的
proxyTargetClass
设置,也提供了对单个bean的动态代理配置preserveTargetClass
.- 调用buildAdvisors对
specificInterceptors
进行适配,封装成advisor.有兴趣的可以看看org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap
.- 配置
advisors
、targetSource
、frozen
等属性后,进行动态代理的创建.proxyFactory.getProxy(getProxyClassLoader())
,进行动态代理生成.
getProxy: 根据当前bean选择JDK或者CGLIB动态代理
- org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
// 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy
// 分别用于JDK和CGLIB代理类的生成,其getProxy方法则用于获取具体的代理对象
return createAopProxy().getProxy(classLoader);
}
ProxyFactory
是ProxyCreatorSupport
的子类,在ProxyCreatorSupport
中有一个createAopProxy
方法,从这里可以获取到具体的代理工厂类.
- org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
// 激活AdvisedSupportListener监听器
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
- activate方法主要是用来激活AdvisedSupportListener的.
- 重点方法是这个:getAopProxyFactory().createAopProxy(this);其中,
getAopProxyFactory
中存储了一个DefaultAopProxyFactory
,它实现了AopProxyFactory
接口,接口方法createAopProxy
才是真正获取代理工厂的地方.
- org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果要代理的类本身就是接口
// 或者它已经是JDK的代理类(Proxy子类)
// 使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用CGLIB动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 接口->JDK动态代理
return new JdkDynamicAopProxy(config);
}
}
这里就会看到我们很熟悉的一个逻辑:实现了接口的bean,Spring会使用JDK动态代理;否则使用CGLIB代理.
工厂模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy
代理策略选择由于篇幅的原因,我选择讲解JdkDynamicAopProxy
这种模式生成代理的源码解析.
- org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
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);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// JdkDynamicAopProxy本身实现了InvocationHandler接口
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
关于JDK如何生成动态代理的原理,这里不做过多的分析了,这在我之前的博客中有关于JDK和CGLIB生成Proxy的文章,不了解的读者可以去看看:
点我前往
在生成代理之后,Proxy就会调用InvocationHandler.invoke
方法,所以关于Spring AOP的代理拦截链执行流程,我们直接去到invoke
解析即可。
- org.springframework.aop.framework.JdkDynamicAopProxy#invoke
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler
首先,JdkDynamicAopProxy实现了InvocationHandler接口,动态代理类最终会执行
InvocationHandler.invoke.
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();
}
// 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型
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;
// 是否暴露代理引用
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);
// 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.
// 如果该方法上没有匹配的拦截器,直接反射调用Method.invoke(target,args)
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...
// 创建ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 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);
}
}
}
- Spring AOP不对equals和hashCode做代理.
- 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型.
- 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可
- 查看当前配置判断是否暴露代理引用,可以来解决this调用引起的代理失效等问题.
- 从targetSource中获取target信息.获取当前method的拦截链路.
getInterceptorsAndDynamicInterceptionAdvice
会对method的拦截链进行缓存,如果没有缓存,会执行org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
重新对method进行match.- 从
getInterceptorsAndDynamicInterceptionAdvice
获取到chain之后,如果chain为空,那么直接激活method.- 如果chain不为空,生成
ReflectiveMethodInvocation
,从JavaDoc可以知道,这是一个Spring实现了AOP Alliance MethodInvocation
接口的类,关键方法:invokeJoinpoint
(激活连接点方法)、proceed
(执行拦截链逻辑).- 执行proceed.
- 处理返回值。包装此返回值(如果有必要作为代理),并验证没有将null作为原语返回。这是什么意思呢:假设方法返回的是int,增强around方法返回了null,这就会报错,因为基础数据类型都有默认值.
- 释放资源、重新设置一次代理引用.
这里最关键的的看chain的执行过程,整个Spring AOP拦截链执行的过程采用了一种递归的方式,值得一品.
代理类执行链路
- org.springframework.aop.framework.ReflectiveMethodInvocation#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();
}
// 从0开始执行,每次递归进来都会+1
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);
}
}
- 在遇到
AfterThrowing
、AfterRetruning
、After
这类advice的时候,它们会执行mi.proceed
回到chain中.- 回到chain中后,列表索引自增,往下执行下一个advice.
- 依次递归,直到遇到
Around
通知,执行around.- 在around中执行
joinPoint.proceed
又会回到chain中.- 递归到
Before
,执行before
,然后回到around的后置代码块中
.- 回溯到
after
、afterReturning
,如果有异常,执行afterThrowing
.
执行流程图
proceed总结
- 1. 生成代理类通过工厂模式进行生成,实现接口默认使用JDK动态代理,否则使用CGLIB
- 2. Spring AOP通过后置处理器的
postProcessAfterInitialization
方法调用wrapIfNessary
对Bean进行代理并替换. - 3. 代理类执行拦截链通过chain进行递归proceed来执行每个通知的方法
网友评论