0x5 Spring系列:深入聊一聊 Spring AOP 实现机制【二】
2: 扫描容器中的切面,创建 PointcutAdvisor对象
在spring ioc流程加载的过程中,会触发 beanPostProcessor
扩展接口,
而AnnotationAwareAspectJAutoProxyCreator
又是SmartInstantiationAwareBeanPostProcessor
的子类,所以该扩展接口正是 aop 实现的入口。
该接口的触发在实例化 bean 之后,初始化 bean之前,具体来看:
@Override
public
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if
(!StringUtils.hasLength(beanName) || !
this
.targetSourcedBeans.contains(beanName)) {
//advisedBeans
用于存储不可代理的
bean
,如果包含直接返回
if
(
this
.advisedBeans.containsKey(cacheKey)) {
return
null
;
}
//
判断当前
bean
是否可以被代理,然后存入
advisedBeans
if
(isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this
.advisedBeans.put(cacheKey,
Boolean
.FALSE);
return
null
;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
//
到这里说明该
bean
可以被代理,所以去获取自定义目标类,如果没有定义,则跳过。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if
(targetSource !=
null
) {
if
(StringUtils.hasLength(beanName)) {
this
.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this
.proxyTypes.put(cacheKey, proxy.getClass());
//
如果最终可以获得代理类,则返回代理类,直接执行实例化后置通知方法
return
proxy;
}
return
null
;
}
来看一下判定 bean 是否被代理的方法依据:
@Override
protected
boolean isInfrastructureClass(Class<?> beanClass) {
return
(
super
.isInfrastructureClass(beanClass) ||
(
this
.aspectJAdvisorFactory !=
null
&&
this
.aspectJAdvisorFactory.isAspect(beanClass)));
}
private
boolean
hasAspectAnnotation
(Class<?> clazz) {
//
判定当前类是否有
Aspect
注解,如果有,则不能被代理
return
(AnnotationUtils.findAnnotation(clazz, Aspect.class) !=
null
);
}
protected boolean isInfrastructureClass(Class<?> beanClass) {
//
判定当前
bean
是否是
Advice
、
Pointcut
、
Advisor
、
AopInfrastructureBean
等子类或实现类,如果是,则不能被代理
boolean retVal = Advice.
class
.isAssignableFrom(beanClass) ||
Pointcut.
class
.isAssignableFrom(beanClass) ||
Advisor.
class
.isAssignableFrom(beanClass) ||
AopInfrastructureBean.
class
.isAssignableFrom(beanClass);
if
(retVal && logger.isTraceEnabled()) {
logger.trace(
"Did not attempt to auto-proxy infrastructure class ["
+ beanClass.getName() +
"]"
);
}
return
retVal;
}
重点来看 shouldSkip方法:
@Override
protected
boolean
shouldSkip
(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
//
获取所有的候选顾问类
Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for
(Advisor advisor : candidateAdvisors) {
if
(advisor
instanceof
AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return
true
;
}
}
return
super
.shouldSkip(beanClass, beanName);
}
上述代码通过findCandidateAdvisors()
方法来获取所有的候选 advisor:
@Override
protected
List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
//
获得
Advisor
实现类
List<Advisor> advisors =
super
.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
//
将
@Aspect
注解类,
解析成
Advisor
if
(
this
.aspectJAdvisorsBuilder !=
null
) {
advisors.addAll(
this
.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return
advisors;
}
继续跟进buildAspectJAdvisors
方法,会触发ReflectiveAspectJAdvisorFactory
中的getAdvisors
方法:
@Override
public
List<Advisor>
getAdvisors
(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//
从
aspectMetadata
中获取
Aspect()
标注的类
class
对象
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//
获取
Aspect()
标注的类名
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new
LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors =
new
LinkedList<>();
//
遍历该类所有方法,根据方法判断是否能获取到对应
pointCut
,如果有,则生成
advisor
对象
for
(Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if
(advisor !=
null
) {
advisors.
add
(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if
(!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor =
new
SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.
add
(
0
, instantiationAdvisor);
}
// Find introduction fields.
//
获取
@DeclareParents
注解修饰的属性(并不常用)
for
(Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if
(advisor !=
null
) {
advisors.
add
(advisor);
}
}
return
advisors;
}
继续来看getAdvisor
方法:
@Override
@Nullable
public
Advisor
getAdvisor
(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int
declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//
根据候选方法名,来获取对应的
pointCut
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if
(expressionPointcut ==
null
) {
return
null
;
}
//
如果能获取到
pointCut
,则将切点表达式
expressionPointcut
、当前
对象
ReflectiveAspectJAdvisorFactory
、
方法名等包装成
advisor
对象
return
new
InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this
, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
可以看到方法将切面相关的类,封装成InstantiationModelAwarePointcutAdvisorImpl
对象,也就是Advisor 对象。
来看下上面获取切面的方法,规则就是遍历方法,根据注解判断:
protected
static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
//
定义
class
对象数组,如果方法中有以下注解中任何一种,则返回该注解
Class<?>[] classesToLookFor = new Class<?>[] {
Before.
class
, Around.
class
, After.
class
, AfterReturning.
class
, AfterThrowing.
class
, Pointcut.
class
};
for
(Class<?> c : classesToLookFor) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if
(foundAnnotation !=
null
) {
return
foundAnnotation;
}
}
return
null
;
}
我们继续来看 Advisor 对象的构造方法。
InstantiationModelAwarePointcutAdvisorImpl
的构造方法会触发构造通知对象:
public
Advice
getAdvice
(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int
declarationOrder, String aspectName) {
//......
//
根据注解类型,匹配对应的通知类型
switch
(aspectJAnnotation.getAnnotationType()) {
//
前置通知
case
AtBefore:
springAdvice =
new
AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break
;
//
最终通知
case
AtAfter:
springAdvice =
new
AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break
;
//
后置通知
case
AtAfterReturning:
springAdvice =
new
AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if
(StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break
;
//
异常通知
case
AtAfterThrowing:
springAdvice =
new
AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if
(StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break
;
//
环绕通知
case
AtAround:
springAdvice =
new
AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break
;
//
切面
case
AtPointcut:
if
(logger.isDebugEnabled()) {
logger.debug(
"Processing pointcut '"
+ candidateAdviceMethod.getName() +
"'"
);
}
return
null
;
default
:
throw
new
UnsupportedOperationException(
"Unsupported advice type on method: "
+ candidateAdviceMethod);
}
//......
}
可以看到,根据@Aspect
类中方法的注解类型,生成对应的advice
,并通过通知的构造方法,将通知增强方法,切面表达式传入到通知当中。
InstantiationModelAwarePointcutAdvisorImpl
对象到这里构造完毕。
3: 生成代理类
上面创建advisor
的逻辑发生在扩展接口中的postProcessBeforeInstantiation
,实例化之前执行,如果有自定义的TargetSource
指定类,则则直接生成代理类,并直接执行初始化之后的方法postProcessAfterInitialization
。这种情况使用不多,常规代理类还是在postProcessAfterInitialization
中创建,也就是 IOC 最后一个扩展方法。
@Override
public
Object
postProcessAfterInitialization(
@Nullable
Object
bean,
String
beanName) throws BeansException {
if
(bean !=
null
) {
Object
cacheKey = getCacheKey(bean.getClass(), beanName);
//
处理循环依赖的判断
if
(!
this
.earlyProxyReferences.contains(cacheKey)) {
return
wrapIfNecessary(bean, beanName, cacheKey);
}
}
return
bean;
}
protected
Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if
(StringUtils.hasLength(beanName) &&
this
.targetSourcedBeans.contains(beanName)) {
return
bean;
}
if
(
Boolean
.FALSE.equals(
this
.advisedBeans.
get
(cacheKey))) {
return
bean;
}
if
(isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this
.advisedBeans.put(cacheKey,
Boolean
.FALSE);
return
bean;
}
// Create proxy if we have advice.
//
获取到合适的
advisor
,如果为空。如果不为空,则生成代理类。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName,
null
);
if
(specificInterceptors != DO_NOT_PROXY) {
this
.advisedBeans.put(cacheKey,
Boolean
.TRUE);
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;
}
上述方法通过调用getAdvicesAndAdvisorsForBean()
方法来获取advisor
,该方法最终会调用findEligibleAdvisors()
,Eligible
意为有资格的,合适的。具体来看下:
protected
List
<Advisor> findEligibleAdvisors(
Class
<?>
beanClass
,
String
beanName
) {
List
<Advisor> candidateAdvisors = findCandidateAdvisors();
//
这里会对获取的
advisor
进行筛选
List
<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//
添加一个默认的
advisor
,执行时用到。
extendAdvisors(eligibleAdvisors);
if
(!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return
eligibleAdvisors;
}
最终的筛选规则在AopUtils
中:
public
static
List
<Advisor> findAdvisorsThatCanApply(
List
<Advisor> candidateAdvisors,
Class
<?>
clazz
) {
//......
for
(Advisor candidate : candidateAdvisors) {
if
(candidate
instanceof
IntroductionAdvisor) {
// already processed
continue
;
}
//
调用
canApply
方法,遍历所有的方法进行匹配
if
(canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
//......
}
调用canApply
方法,遍历被代理类的所有的方法,跟进切面表达式进行匹配,如果有一个方法匹配到,也就意味着该类会被代理。
匹配方法是借助org.aspectj.weaver.internal.tools
实现,也就是AspectJ
框架中的工具类,有兴趣的可以自行查看。
重点来看一下代理生成方式:
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."
);
}
//
如果代理目标是接口或者
Proxy
类型,则走
jdk
类型
if
(targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return
new
JdkDynamicAopProxy(config);
}
return
new
ObjenesisCglibAopProxy(config);
}
else
{
return
new
JdkDynamicAopProxy(config);
}
}
上述方法通过三个变量来进行筛选代理方法:
· optimize
:官方文档翻译为设置代理是否应执行积极的优化,默认为false。
· proxyTargetClass
:这个在上面已经提到了,AopAutoConfiguration
中指定,默认为true,也就是选择使用 cglib 代理。可以看到该变量和optimize
意义一样,之所以这么做,个人理解是为了可以在不同的场景中使用。
· hasNoUserSuppliedProxyInterfaces
:是否指定了实现接口。什么意思呢?
hasNoUserSuppliedProxyInterfaces
方法如下:
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
主要就是判断AdvisedSupport
中interfaces
变量中是否设置了接口,
意思是如果一个类实现了接口,把接口设置到该方法的变量中,但是不是一定会设置到该变量中,具体设置接口的代码如下:
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
//......
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//......
}
可以看到如果proxyTargetClass
为 true,上述方法将不再执行,也就意味着interfaces
变量不再赋值。同时,只要为类代理,默认会走 CGLIB 方式。
三:Spring Boot 1.x 版本和 2.x 版本中 AOP配置变动
配置类AopAutoConfiguration
:
1.5x版本:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {
}
2.x版本:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
在SpringBoot2.x中最主要的变化就是proxy-target-class
默认为true,意味着类代理的时候全部走cglib代理方式,只有为接口代理时才走jdk代理(注意:这里为接口代理,不是指代理目标类是否实现了接口)。所以,在使用springboot2.x的版本中,除了代理目标类是接口外,其余的代理方式全部采用cglib类型。
总结
Springboot
通过自动装配AopAutoConfiguration
配置类,默认自动开启 AOP 功能。通过注册AnnotationAwareAspectJAutoProxyCreator
类,来扫描创建所有的Advisor
,再通过 Advisor
在 Spring IOC的扩展接口中,通过各种设置的匹配规则,来判断是否设置代理,最终生成代理类,注入容器 Spring中
具体代理类如何调用执行呢?后面会详细介绍。
- 点赞
- 收藏
- 关注作者
评论(0)