在上篇文章
中我们搭建了一个阅读源码的 demo 工程,然后简单介绍了一下 @EnableAspectJAutoProxy
注解,这个注解最重要的功能就是为向 Spring 中注入了一个 beanAnnotationAwareAspectJAutoProxyCreator
, 本篇文章就继续来撸 AOP 的源码
前文已经简单提到了这个类的功能,不过这里还是要先看一下这个类的继承图
观察类图可知,AnnotationAwareAspectJAutoProxyCreator 这个类间接实现了 BeanPostProcessor 接口。还记得我们之前在对 SpringIOC 的源码进行解析时提到过,Spring 在实例化 Bean 的前后会分别调用方法 postProcessBeforeInstantiation
和postProcessAfterInstantiation
而 AOP 的整体逻辑就是通过这两个方法来实现的
postProcessBeforeInstantiation
首先看一下这个 postProcessBeforeInstantiation
方法,它是在 bean 实例化之前调用的,主要是针对切面类。这个方法不在 AnnotationAwareAspectJAutoProxyCreator 这个类中,而是在其父类 AbstractAutoProxyCreator 中
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}
// 加载所有增强
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
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;
}
加载增强
上方代码中最重要的一个方法就是 shouldSkip 方法了,这个方法被 AspectJAwareAdvisorAutoProxyCreator 所重载
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 查找所有标识了 @Aspect 注解的类,这里是重点,接着往下看
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor) {if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {return true;}
}
}
return super.shouldSkip(beanClass, beanName);
}
protected List<Advisor> findCandidateAdvisors() {return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findCandidateAdvisors() {List<Advisor> advisors = super.findCandidateAdvisors();
//buildAspectJAdvisors 是重点
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
一个长方法 buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
// 所有 Aspect 类的名称集合
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {synchronized (this) {
aspectNames = this.aspectBeanNames;
// 这个双重检查是不是在学习安全的单例模式的时候见过
if (aspectNames == null) {List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
// 获取所有 Bean 名称
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 判断是否符合条件,比如说有时会排除一些类,不让这些类注入进 Spring
if (!isEligibleBean(beanName)) {continue;}
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {continue;}
// 判断 Bean 的 Class 上是否标识 @Aspect 注解
if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 下一步说,重点的重点
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 将解析的 Bean 名称及类上的增强缓存起来, 每个 Bean 只解析一次
this.advisorsCache.put(beanName, classAdvisors);
}
else {this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name'" + beanName +
"'is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
// 从缓存中获取当前 Bean 的切面实例,如果不为空,则指明当前 Bean 的 Class 标识了 @Aspect,且有切面方法
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
}
else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
生成增强
advisorFactory.getAdvisors 方法会从 @Aspect 标识的类上获取 @Before,@Pointcut 等注解的信息及其标识的方法的信息,生成增强
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校验类的合法性相关
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
// 获取这个类所有的增强方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 生成增强实例
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {advisors.add(advisor);
}
}
return advisors;
}
// 获取类的的方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {final List<Method> methods = new LinkedList<Method>();
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
// 在 @Aspect 标识的类内部排除 @Pointcut 标识之外的所有方法,得到的方法集合包括继承自父类的方法,包括继承自 Object 的方法
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {methods.add(method);
}
}
});
// 对得到的所有方法排序,// 如果方法标识了切面注解,则按 @Around, @Before, @After, @AfterReturning, @AfterThrowing 的顺序排序
// 如果没有标识这些注解,则按方法名称的字符串排序,
// 有注解的方法排在无注解的方法之前
// 最后的排序应该是这样的 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class。。。Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}
调用生成增强实例的方法
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 再次校验类的合法性
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 切点表达式的包装类里面包含这些东西:execution(public * cn.shiyujun.service.IOCService.hollo(..))
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {return null;}
// 根据方法、切点、AOP 实例工厂、类名、序号生成切面实例,详细代码往下看
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 查询方法上的切面注解,根据注解生成相应类型的 AspectJAnnotation, 在调用 AspectJAnnotation 的构造函数的同时
// 根据注解 value 或 pointcut 属性得到切点表达式,有 argNames 则设置参数名称
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 过滤那些不含 @Before, @Around, @After, @AfterReturning, @AfterThrowing 注解的方法
if (aspectJAnnotation == null) {return null;}
// 生成带表达式的切面切入点,设置其切入点表达式
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
InstantiationModelAwarePointcutAdvisorImpl 的构造方法
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 重点在这里
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
// 再往下看
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
生成增强
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 又是一次校验
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {return null;}
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type:" +
"Offending method'" + candidateAdviceMethod + "'in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {logger.debug("Found AspectJ method:" + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根据注解类型生成不同的通知实例
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);
}
// 设置通知方法所属的类
springAdvice.setAspectName(aspectName);
// 设置通知的序号, 同一个类中有多个切面注解标识的方法时, 按上方说的排序规则来排序,// 其序号就是此方法在列表中的序号,第一个就是 0
springAdvice.setDeclarationOrder(declarationOrder);
// 获取通知方法的所有参数
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
// 将通知方法上的参数设置到通知中
if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);
}
// 计算参数绑定工作,此方法详解请接着往下看
springAdvice.calculateArgumentBindings();
return springAdvice;
}
}
校验方法参数并绑定
public synchronized final void calculateArgumentBindings() {if (this.argumentsIntrospected || this.parameterTypes.length == 0) {return;}
int numUnboundArgs = this.parameterTypes.length;
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
// 切面注解标识的方法第一个参数要求是 JoinPoint, 或 StaticPart,若是 @Around 注解则也可以是 ProceedingJoinPoint
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {numUnboundArgs--;}
else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {numUnboundArgs--;}
if (numUnboundArgs > 0) {
// 绑定属性
bindArgumentsByName(numUnboundArgs);
}
this.argumentsIntrospected = true;
}
private void bindArgumentsByName(int numArgumentsExpectingToBind) {if (this.argumentNames == null) { // 获取方法参数的名称
this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
}
if (this.argumentNames != null) {
// 往下看
bindExplicitArguments(numArgumentsExpectingToBind);
}
else {throw new IllegalStateException("Advice method [" + this.aspectJAdviceMethod.getName() + "]" +
"requires" + numArgumentsExpectingToBind + "arguments to be bound by name, but" +
"the argument names were not specified and could not be discovered.");
}
}
private void bindExplicitArguments(int numArgumentsLeftToBind) {
// 此属性用来存储方法未绑定的参数名称,及参数的序号
this.argumentBindings = new HashMap<String, Integer>();
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
if (this.argumentNames.length != numExpectedArgumentNames) {
throw new IllegalStateException("Expecting to find" + numExpectedArgumentNames +
"arguments to bind by name in advice, but actually found" +
this.argumentNames.length + "arguments.");
}
// So we match in number...,argumentIndexOffset 代表第一个未绑定参数的顺序
int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
// 存储未绑定的参数名称及其顺序的映射关系
this.argumentBindings.put(this.argumentNames[i], i);
}
// Check that returning and throwing were in the argument names list if
// specified, and find the discovered argument types.
// 如果是 @AfterReturning 注解的 returningName 有值,验证,解析,同时得到定义返回值的类型
if (this.returningName != null) {if (!this.argumentBindings.containsKey(this.returningName)) {
throw new IllegalStateException("Returning argument name'" + this.returningName +
"'was not bound in advice arguments");
}
else {Integer index = this.argumentBindings.get(this.returningName);
this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
}
}
// 如果是 @AfterThrowing 注解的 throwingName 有值,验证,解析,同时得到抛出异常的类型
if (this.throwingName != null) {if (!this.argumentBindings.containsKey(this.throwingName)) {
throw new IllegalStateException("Throwing argument name'" + this.throwingName +
"'was not bound in advice arguments");
}
else {Integer index = this.argumentBindings.get(this.throwingName);
this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
}
}
// configure the pointcut expression accordingly.
configurePointcutParameters(argumentIndexOffset);
}
private void configurePointcutParameters(int argumentIndexOffset) {
int numParametersToRemove = argumentIndexOffset;
if (this.returningName != null) {numParametersToRemove++;}
if (this.throwingName != null) {numParametersToRemove++;}
String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove];
Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length];
Class<?>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
int index = 0;
for (int i = 0; i < this.argumentNames.length; i++) {if (i < argumentIndexOffset) {continue;}
if (this.argumentNames[i].equals(this.returningName) ||
this.argumentNames[i].equals(this.throwingName)) {continue;}
pointcutParameterNames[index] = this.argumentNames[i];
pointcutParameterTypes[index] = methodParameterTypes[i];
index++;
}
// 剩余的未绑定的参数会赋值给 AspectJExpressionPointcut(表达式形式的切入点)的属性,以备后续使用
this.pointcut.setParameterNames(pointcutParameterNames);
this.pointcut.setParameterTypes(pointcutParameterTypes);
}
未完待续
限于平台字数限制,本篇文章就到这里