本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试。
记录日期:2022.1.21
大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习。
文章目录
框架原理 - Spring(五) 之 Spring AOP 基于注解解析
< aop:aspectj-autoproxy /> 标签解析
<aop:aspectj-autoproxy/ >
标签用于开启对于AOP注解的支持,我们先看看这个标签的解析流程,它使用 AspectJAutoProxyBeanDefinitionParser
解析器解析。
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
AspectJAutoProxyBeanDefinitionParser#parse()
分析一下 AspectJAutoProxyBeanDefinitionParser#parse()
方法的代码逻辑:
-
尝试注册或者升级一个名为
"org.springframework.aop.config.internalAutoProxyCreator"
,类型为AnnotationAwareAspectJAutoProxyCreator
的自动代理创建者的bean定义。 -
解析
<aop:include />
子标签,扩展自动代理创建者的bean定义。该标签用于指定一些模式从而根据beanName筛选切面类。
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 尝试注册或升级 AnnotationAwareAspectJAutoProxyCreator 自动代理创建者
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 解析 <aop:include /> 子标签
extendBeanDefinition(element, parserContext);
return null;
}
registerAspectJAnnotationAutoProxyCreatorIfNecessary()
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法大致可分为三个步骤:
- 尝试注册或者升级一个名为
"org.springframework.aop.config.internalAutoProxyCreator"
,类型为AnnotationAwareAspectJAutoProxyCreator
的自动代理创建者的bean定义。 - 尝试解析
<aop:aspectj-autoproxy />
标签的proxy-target-class
与expose-proxy
属性。proxy-target-class
属性为true时,表示使用CGLIB动态代理;为false时,表示使用JDK动态代理,但是如果对应类没有实现接口时,也会使用CGLIB动态代理。expose-proxy
属性是否要对内部方法实现增强。
- 方法字面意思是尝试注册组件,这里的注册其实是调用解析上下文的
registerComponent
方法将 bean 注册到CompositeComponentDefinition
对象的内部集合中或者广播事件。
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 尝试注册或升级 AnnotationAwareAspectJAutoProxyCreator 自动代理创建者
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 尝试解析<aop:aspectj-autoproxy/>标签的proxy-target-class与expose-proxy属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 尝试注册内部组件
registerComponentIfNecessary(beanDefinition, parserContext);
}
registerAspectJAnnotationAutoProxyCreatorIfNecessary()
它内部继续调用 registerOrEscalateApcAsRequired
方法,入参cls属性传入的是 AnnotationAwareAspectJAutoProxyCreator
。
在解析 <aop:config />
标签时,是尝试注册 AspectJAwareAdvisorAutoProxyCreator
,但是我们看UML类图可以看到 ,AnnotationAwareAspectJAutoProxyCreator
是 AspectJAwareAdvisorAutoProxyCreator
的子类,所以说明,当我们同时存在 <aop:config />
标签和 <aop:aspectj-autoproxy />
标签时,最终注册的肯定是 AnnotationAwareAspectJAutoProxyCreator
。
AnnotationAwareAspectJAutoProxyCreator
和 AspectJAwareAdvisorAutoProxyCreator
相比,前者支持了 AspectJ
注解来配置AOP。
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 入参cls属性为 AnnotationAwareAspectJAutoProxyCreator
// 继续调用 registerOrEscalateApcAsRequired 方法
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果容器内包含名为org.springframework.aop.config.internalAutoProxyCreator的bean
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 获取对应bean
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 比较优先级,同之前
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 如果不包含,注册bean
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
useClassProxyingIfNecessary()
该方法用于尝试解析 <aop:aspectj-autoproxy />
标签的 proxy-target-class
与 expose-proxy
属性。
proxy-target-class
属性- 值为true时,表示使用CGLIB动态代理。
- 值为false时,表示使用JDK动态代理,但是如果对应类没有实现接口时,也会使用CGLIB动态代理。
expose-proxy
属性- 是否要对内部方法实现增强。
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
/**
获取并处理 proxy-target-class 属性
false表示使用JDK动态代理,true表示使用CGLIB动态代理。
但是对于一些没有接口实现的类来说,即使设置为 false 也会使用 CGlib 进行代理
*/
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
// 为之前注册的 ProxyCreator 添加一个名为 proxyTargetClass 的属性,值为 true
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 获取并处理 expose-proxy 标签,实现对于内部方法调用的 AOP 增强
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
// 为之前注册的 ProxyCreator 添加一个名为 exposeProxy 的属性,值为 true
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
registerComponentIfNecessary()
该方法用于注册组件,这里的注册是指存放到 parserContext
解析上下文中的 CompositeComponentDefinition
对象的内部 nestedComponents
List集合中或者广播事件。
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
}
}
public void registerComponent(ComponentDefinition component) {
// 获取 CompositeComponentDefinition
CompositeComponentDefinition containingComponent = getContainingComponent();
if (containingComponent != null) {
// 添加到内部集合中
containingComponent.addNestedComponent(component);
}
else {
// 广播事件
this.readerContext.fireComponentRegistered(component);
}
}
extendBeanDefinition()
该方法是用于解析 <aop:include />
子标签,拓展前面注册的自动代理创建者的bean定义。
<aop:include />
子标签的作用是,来指定只有具有指定格式的 @Aspect
切面类才会生效。
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private void extendBeanDefinition(Element element, ParserContext parserContext) {
// 获取注册的自动代理创建者的bean定义
BeanDefinition beanDef =
parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
// 如果当前 <aop:aspectj-autoproxy /> 标签存在子节点
if (element.hasChildNodes()) {
// 添加IncludePatterns属性
addIncludePatterns(element, parserContext, beanDef);
}
}
private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
ManagedList<TypedStringValue> includePatterns = new ManagedList<>();
// 获取子节点集合
NodeList childNodes = element.getChildNodes();
// 遍历子节点
for (int i = 0; i < childNodes.getLength(); i++) {
// 获取对应标签节点
Node node = childNodes.item(i);
if (node instanceof Element) {
Element includeElement = (Element) node;
// 获取name属性值,封装成TypedStringValue
TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
// 设置源,即当前<aop:include/>子标签
valueHolder.setSource(parserContext.extractSource(includeElement));
// 加入到includePatterns中
includePatterns.add(valueHolder);
}
}
// 如果includePatterns不为空
if (!includePatterns.isEmpty()) {
// 设置源,当前<aop:aspectj-autoproxy/>标签
includePatterns.setSource(parserContext.extractSource(element));
// 将includePatterns设置到自动代理创建者的bean定义的属性中
beanDef.getPropertyValues().add("includePatterns", includePatterns);
}
}
所有 <aop:include />
标签配置的name属性值,将会在创建自动代理创建者实例时转换为 Pattern
对象并封装成一个list集合,赋给它的 includePatterns
属性,因此,这里的name值应该是一个正则表达式,可以在 AnnotationAwareAspectJAutoProxyCreator
的 setIncludePatterns
方法和 isEligibleAspectBean
方法中看出来。
@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
@Nullable
private List<Pattern> includePatterns;
// 设置正则表达式模式的列表,匹配符合条件的@AspectJ bean的名称
// 默认值是将所有@AspectJ视为符合条件
public void setIncludePatterns(List<String> patterns) {
this.includePatterns = new ArrayList<>(patterns.size());
for (String patternText : patterns) {
this.includePatterns.add(Pattern.compile(patternText));
}
}
// 检查传入的beanName对应bean是否符合自动代理的条件
protected boolean isEligibleAspectBean(String beanName) {
// 如果没有设置包含模式,即没有<aop:include/>标签,那么默认返回true,表示全部符合条件
if (this.includePatterns == null) {
return true;
}
// 如果设置了包含模式,那么给定的beanName至少匹配一个模式
else {
for (Pattern pattern : this.includePatterns) {
// 如果给定的beanName至少匹配一个模式(正则表达式),就直接返回true
if (pattern.matcher(beanName).matches()) {
return true;
}
}
// 都不匹配,那么返回false
return false;
}
}
...
}
AnnotationAwareAspectJAutoProxyCreator创建代理对象
AnnotationAwareAspectJAutoProxyCreator
是 AspectJAwareAdvisorAutoProxyCreator
的子类,所以它不仅包括了其父类的所有执行创建代理对象相同的逻辑与方法,同时还拓展了支持通过相关 @AspectJ
注解配置AOP的功能。
AnnotationAwareAspectJAutoProxyCreator
重写了 findCandidateAdvisors
方法,在调用父类基于XML的AOP配置时,还支持对于AOP注解配置。
findCandidateAdvisors()
该方法的作用还是与之前相同,用于查找beanFactory中的所有Advisor类型的通知器bean定义并且初始化。
但是它在调用父类的 findCandidateAdvisors
方法(基于XML配置已解析的 Advisor
)之外,还从beanFactory中查找所有具有 @AspectJ
注解的切面bean定义中的通知并构建,将切面类中全部合法的通知方法和引介字段转换为 Advisor
,最后返回所有的 Advisor
集合,这是对Aspect注解配置的支持。
@Nullable
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
@Override
protected List<Advisor> findCandidateAdvisors() {
// 调用父类的findCandidateAdvisors方法查找基于XML配置的已解析的Advisors
List<Advisor> advisors = super.findCandidateAdvisors();
// 从beanFactory中查找所有具有@Aspect注解的切面bean定义并构建
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
// 返回所有解析到的Advisors
return advisors;
}
BeanFactoryAspectJAdvisorsBuilder
BeanFactoryAspectJAdvisorsBuilder
的作用是用于从 beanFactory 检索 @AspectJ
的bean,并基于它们构建 Advisor
的构建者,用于自动代理。
它在 AnnotationAwareAspectJAutoProxyCreator
的初始化是在重写的 initBeanFactory
方法中,它构建的类型是 BeanFactoryAspectJAdvisorsBuilderAdapter
,同时也初始化了 aspectJAdvisorFactory
,用于构建每一个 Advisor
。另一个 beanFactory 是在 BeanFactoryAware
接口中注入的。
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用父类的initBeanFactory方法,初始化父类的advisorRetrievalHelper
super.initBeanFactory(beanFactory);
// 构建aspectJAdvisor工厂,实际类型为ReflectiveAspectJAdvisorFactory
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
// 创建aspectJAdvisor构建者,实际类型为BeanFactoryAspectJAdvisorsBuilderAdapter,它是内部私有类
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
来看一下 BeanFactoryAspectJAdvisorsBuilderAdapter
的实现,其中也是调用了父类的构造器。
private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
public BeanFactoryAspectJAdvisorsBuilderAdapter(
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
super(beanFactory, advisorFactory);
}
@Override
protected boolean isEligibleBean(String beanName) {
// 调用AnnotationAwareAspectJAutoProxyCreator对象的isEligibleAspectBean方法
return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
}
}
// BeanFactoryAspectJAdvisorsBuilder 父类构造器
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
this.beanFactory = beanFactory;
this.advisorFactory = advisorFactory;
}
AspectJAdvisorFactory
AspectJAdvisorFactory
是用于工厂的接口,这些工厂可以从用 @AspectJ
相关注解的类中创建 Advisor
。
而它在 AnnotationAwareAspectJAutoProxyCreator
中构造的实际类型是 ReflectiveAspectJAdvisorFactory
,它可以根据 @AspectJ
组件类内部的通知注解 @Before
、@Around
、@After
、@AfterReturning
、@AfterThrowing
,创建Spring的Advisor通知器,使用反射调用相应的通知方法。
AbstractAspectJAdvisorFactory
提供了对 AspectJAdvisorFactory
类的实现,作为 ReflectiveAspectJAdvisorFactory
的抽象父类,它的作用是进行注解的解析和校验。
我们先来看实现的 isAspect
方法:
- 检查该Class是否存在
@Aspect
注解。 - 检查该Class是否是通过
AcpectJ
编译器编译。
private static final String AJC_MAGIC = "ajc$";
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
// 检查该类是否存在 @AspectJ 注解
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
// 检查该Class是否是通过AcpectJ编译器编译
// 默认情况下,IntelliJ IDEA 使用 javac 编译器,我们可以手动设置使用AJC编译器
private boolean compiledByAjc(Class<?> clazz) {
// AJTypeSystem竭尽全力在代码样式和注释样式方面提供统一的外观。
// 因此,没有“干净”的方法来区分它们。这里我们依赖于AspectJ编译器的一个实现细节。
// 那就是所有的变量都以"ajc$"开头。
for (Field field : clazz.getDeclaredFields()) {
if (field.getName().startsWith(AJC_MAGIC)) {
return true;
}
}
return false;
}
再来看实现的 validate
方法,用于校验切面类。
@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
// 如果父类具有@Aspect注解且不是抽象的,则抛出异常
if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
!Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
aspectClass.getSuperclass().getName() + "]");
}
/**
* 获取当前切面类的AjType,即返回给定 Java 类型的 AspectJ 运行时类型表示形式
* AjType是AspectJ程序中切面类的运行时表示形式,区别于 java.lang.class,
* 可以从中获取切入点、通知、declare和其他 AspectJ 类型的成员等信息
*/
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
// 如果不是切面类,则抛出异常
if (!ajType.isAspect()) {
throw new NotAnAtAspectException(aspectClass);
}
// 如果@Aspect注解的value属性值被设置为"percflow()",则抛出异常
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
"This is not supported in Spring AOP.");
}
// 如果@Aspect注解的value属性值被设置为"percflowbelow()",则抛出异常
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
"This is not supported in Spring AOP.");
}
}
AbstractAspectJAdvisorFactory
中定义了 AspectJ
相关注解的查找、解析、封装和校验,具体代码如下:
public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {
// 所有AspectJ相关注解数组
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
// 参数名称发现器,构造的是内部类实例
protected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer();
protected enum AspectJAnnotationType {
AtPointcut, AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing
}
/*
查找并返回给定方法上的第一个 AspectJ 注解,方法上理应只有一个AspectJ注解
找到某一个注解即停止查找,然后将当前方法封装为基于该注解的AspectJAnnotation,
查找注解的顺序为数组的顺序,如果一个方法同时被多个注解定义,则按照数组顺序优先选取一个后,将其他注解短路并抛弃。
*/
@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// 遍历AspectJ相关注解数组,按顺序查找
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
// 查找对应方法上是否存在该注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
// 找到之后就返回
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
// 用于封装AspectJ相关注解的AspectJAnnotation
protected static class AspectJAnnotation<A extends Annotation> {
private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"};
private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap<>(8);
static {
annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
}
private final A annotation;
private final AspectJAnnotationType annotationType;
private final String pointcutExpression;
private final String argumentNames;
public AspectJAnnotation(A annotation) {
this.annotation = annotation;
this.annotationType = determineAnnotationType(annotation);
try {
this.pointcutExpression = resolveExpression(annotation);
Object argNames = AnnotationUtils.getValue(annotation, "argNames");
this.argumentNames = (argNames instanceof String ? (String) argNames : "");
}
catch (Exception ex) {
throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex);
}
}
private AspectJAnnotationType determineAnnotationType(A annotation) {
AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
if (type != null) {
return type;
}
throw new IllegalStateException("Unknown annotation type: " + annotation);
}
private String resolveExpression(A annotation) {
for (String attributeName : EXPRESSION_ATTRIBUTES) {
Object val = AnnotationUtils.getValue(annotation, attributeName);
if (val instanceof String) {
String str = (String) val;
if (!str.isEmpty()) {
return str;
}
}
}
throw new IllegalStateException("Failed to resolve expression: " + annotation);
}
}
// 内部类
private static class AspectJAnnotationParameterNameDiscoverer implements ParameterNameDiscoverer {
@Override
@Nullable
public String[] getParameterNames(Method method) {
if (method.getParameterCount() == 0) {
return new String[0];
}
AspectJAnnotation<?> annotation = findAspectJAnnotationOnMethod(method);
if (annotation == null) {
return null;
}
StringTokenizer nameTokens = new StringTokenizer(annotation.getArgumentNames(), ",");
if (nameTokens.countTokens() > 0) {
String[] names = new String[nameTokens.countTokens()];
for (int i = 0; i < names.length; i++) {
names[i] = nameTokens.nextToken();
}
return names;
}
else {
return null;
}
}
// 钩子方法
@Override
@Nullable
public String[] getParameterNames(Constructor<?> ctor) {
throw new UnsupportedOperationException("Spring AOP cannot handle constructor advice");
}
}
}
而 ReflectiveAspectJAdvisorFactory
中封装具体的 advisor
的生成逻辑,后面会介绍 getAdvisors
方法的实现,这里看一下在该类中的相关代码,主要在于方法比较器,可以用于比较基于注解的通知方法并排序。
// Exclude @Pointcut methods
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
private static final Comparator<Method> adviceMethodComparator;
// 静态代码块用于加载比较器
static {
// 主要比较器,采用ConvertingComparator,先对传入的参数使用转换器进行转换,随后使用比较器进行比较
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
// 实例比较器,order值就是InstanceComparator中定义的注解的索引,如果没有这些注解就是最大值5
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
// 实例转换器,将通知方法转换为一个AspectJAnnotation对象,该方法上标注的注解,就是对应对象的类型
(Converter<Method, Annotation>) method -> {
// 查找方法的注解,找到某一个注解即停止查找,然后将当前方法封装为基于该注解的AspectJAnnotation
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
// 次要比较器,比较方法名
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}
buildAspectJAdvisors()【重点】
回到 findCandidateAdvisors
中,调用 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
。
该方法的作用是在当前bean容器中查找具有 @AspectJ
注解的切面bean,并基于它们的配置构建对应的 Advisor
,将切面类中全部合法的通知方法和引介字段转换为 Advisor
,最后返回所有的 Advisor
集合。
该方法还会使用缓存,第一次进入时将查找到的通知器名称都存入 aspectBeanNames
缓存集合中,后续进来时直接从缓存中获取(这要求是单例的切面bean)。
缓存的原因是重写的 findCandidateAdvisors
方法会被多次调用。
// 切面的名称缓存
@Nullable
private volatile List<String> aspectBeanNames;
// 通知器缓存
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();
// 切面工厂缓存
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>();
public List<Advisor> buildAspectJAdvisors() {
// 获取切面名称缓存集合
List<String> aspectNames = this.aspectBeanNames;
// 集合为null,初始化切面名称缓存
// 双重校验锁
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 保存构建的Advisor集合
List<Advisor> advisors = new ArrayList<>();
// 初始化aspectNames集合
aspectNames = new ArrayList<>();
// 获取全部Object类型的bean定义的beanName数组
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历beanName数组,查找所有切面类中的头通知器
for (String beanName : beanNames) {
// 判断切面bean的名称是否合格
// 该方法默认是返回true,在子类 AnnotationAwareAspectJAutoProxyCreator 中重写
// 用之前的正则表达式进行匹配,检查是否符合子标签<aop:include/>的配置模式
if (!isEligibleBean(beanName)) {
continue;
}
// 获取当前beanName对应的bean定义的所属类的类型
Class<?> beanType = this.beanFactory.getType(beanName, false);
// 类型为null则跳过
if (beanType == null) {
continue;
}
// 判断是否是切面类,即判断当前类以及它继承的超类或者实现的接口上是否具有@Aspect注解
// 这个isAspect方法在前面已经分析过,这里说明了一个问题
// 只有该类被注册到容器中(比如加@Component注解),才可以解析@AspectJ注解
if (this.advisorFactory.isAspect(beanType)) {
// 添加beanName到切面名称缓存集合
aspectNames.add(beanName);
// 封装class和name到切面元数据
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 如果没有设置@Aspect注解的value属性值,那么就是默认就是单例的切面类
// value可以设置为值有PERTHIS、PERTARGET、PERCFLOW、PERCFLOWBELOW、PERTYPEWITHIN,可以设置切面类的生命周期
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 新建一个BeanFactoryAspectInstanceFactory工厂对象,用于创建AspectJ 切面实例
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 通过advisorFactory调用getAdvisors方法
// 将当前切面类中全部合法的通知方法和引介字段转换为Advisor通知器集合
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 如果当前切面类是单例bean
if (this.beanFactory.isSingleton(beanName)) {
// 是单例bean,则将当前切面类beanName和内部的通知器集合存入advisorsCache缓存
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 不是单例bean,则将当前切面类beanName和切面实例工厂存入aspectFactoryCache缓存
this.aspectFactoryCache.put(beanName, factory);
}
// 当前切面类的所有通知器加入到advisors总集合中
advisors.addAll(classAdvisors);
}
// 对于其他切面类的作用域的处理
else {
//如果当前切面bean是单例的,那么抛出异常
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
// 新建一个PrototypeAspectInstanceFactory工厂对象,用于创建AspectJ 切面实例
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 将当前切面类beanName和切面实例工厂存入aspectFactoryCache缓存
this.aspectFactoryCache.put(beanName, factory);
// 当前切面类的所有通知器加入到advisors总集合中
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
// aspectNames赋给aspectBeanNames缓存起来,后续从缓存中直接获取
this.aspectBeanNames = aspectNames;
// 返回通知器集合
return advisors;
}
}
}
// 如果切面名称缓存为空,返回emptyList
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
// 如果切面名称缓存不为空,遍历aspectNames
for (String aspectName : aspectNames) {
// 根据切面名称获取该切面的通知器集合
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
// 如果不为null,说明已缓存
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
// 如果为null,说明这个切面bean不是单例bean,重新获取
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
// 返回通知集合
return advisors;
}
getAdvisors()【重点】
在 buildAspectJAdvisors
代码块中,第一次初始化缓存时调用了 this.advisorFactory.getAdvisors(factory)
。
该方法在 ReflectiveAspectJAdvisorFactory
中被实现,用于为指定切面类上的所有具有通知注解的方法和具有引介注解的字段生成 Advisor,通知方法生成 InstantiationModelAwarePointcutAdvisorImpl
类型的切入点通知器,引介字段生成 DeclareParentsAdvisor
类型的引介通知器,最后返回找到的全部通知器集合。
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 1.1 获取切面类的class
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 1.2 获取切面类的name,就是beanName
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 1.3 校验切面类,见前面解释
validate(aspectClass);
// 2. 翻译注释:使用装饰器包装当前的aspectInstanceFactory对象,使得内部的切面类实例只被创建一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
// 找到的通知器集合
List<Advisor> advisors = new ArrayList<>();
/**
3. getAdvisorMethods获取当前切面类中的全部方法
排除桥接方法、合成方法、具有@Pointcut注解的方法,所以说普通方法也会被加进来
因此还需要继续筛选和处理
*/
for (Method method : getAdvisorMethods(aspectClass)) {
// 4. 处理方法即尝试转换为Advisor通知器
/**
翻译注释:Spring 5.2.7之前,advisors.size()作为第三个参数,以便确定位置。
但是Java7开始,JDK不再按在源代码中声明的方法的顺序返回声明的方法,
因此,对于通过反射发现的所有通知方法,
我们现在将第三个参数declarationOrderInAspect通过硬编码设置为0,
所有的通知的declarationOrder都是0,
返回的通知器实际类型为InstantiationModelAwarePointcutAdvisorImpl,
属于PointcutAdvisor切入点通知器。
*/
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
// 如果可以转换为Advisor通知器则加入通知器集合
advisors.add(advisor);
}
}
// 5. 如果通知器集合不为空,并且属于延迟初始化的切面类,那么在通知器列表头部加入一个SyntheticInstantiationAdvisor同步实例通知器
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 6. 查找并解析引介增强字段,即@DeclareParents注解
for (Field field : aspectClass.getDeclaredFields()) {
// 6.1 从该字段获取引介增强的通知器
//返回的通知器实际类型为DeclareParentsAdvisor,属于IntroductionAdvisor引介通知器
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
// 引介通知器加入通知器集合
advisors.add(advisor);
}
}
// 7. 引介通知器加入通知器集合
return advisors;
}
getAdvisorMethods()
在 getAdvisors
代码块 3
中,获取当前切面类中的全部通知方法并排序,仅排除带有 @Pointcut
注解的方法,所以还包括普通的方法。
// 通知方法筛选过滤器,用于排除@Pointcut注解
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
// 方法比较器,用于比较基于注解的通知方法并排序,它是在静态代码块中被初始化的
private static final Comparator<Method> adviceMethodComparator;
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
/*
传入:切面类、方法回调、方法筛选过滤器
*/
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
// 通过比较器,排序
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
}
return methods;
}
getAdvisor()
在 getAdvisors
代码块 4
中,用于根据通知方法尝试获取通知器。
在 getAdvisorMethods()
方法中仅排除了带有 @Pointcut
注解的方法,还包含了普通的方法,因此在 getAdvisor()
方法还需要进一步过滤,只有具有通知注解的方法才能算是通知方法,最后将该方法封装成一个 InstantiationModelAwarePointcutAdvisorImpl
类型的通知器返回。
@Override
@Nullable
public Advisor getAdvisor(
Method candidateAdviceMethod, // 候选的通知方法
MetadataAwareAspectInstanceFactory aspectInstanceFactory, // 切面类实例工厂(被封装的)
int declarationOrderInAspect, // 声明顺序,目前都是固定传入0
String aspectName // 切面名,即容器中的beanName
) {
// 1. 再一次校验
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 2. 获取当前通知方法对应的切入点实例,封装了当前通知的切入点表达式的信息
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod,
aspectInstanceFactory.getAspectMetadata().getAspectClass()
);
// 3. 如果没有切入点表达式,那么直接返回null(对于普通方法会找不到通知注解,直接返回null)
if (expressionPointcut == null) {
return null;
}
// 4. 新建一个InstantiationModelAwarePointcutAdvisorImpl类型的通知器返回
return new InstantiationModelAwarePointcutAdvisorImpl(
expressionPointcut,
candidateAdviceMethod,
this,
aspectInstanceFactory,
declarationOrderInAspect,
aspectName
);
}
getPointcut()
在 getAdvisor
代码块 2
中,调用该方法获取切入点表达式对象。
该方法用于获取当前通知方法对应的切入点表达式对象,即 AspectJExpressionPointcut
对象,内部的切入点表达式一般都是通知注解的 pointcut
或者 value
属性的值配置。如果是普通方法则会返回null。
一个通知方法上理应只有一个通知注解,如果有多个注解,那么只会有一个生效,只会获取该注解的切入点表达式对象。查找顺序为:Pointcut.class
、Around.class
、Before.class
、After.class
、AfterReturning.class
、AfterThrowing.class
。具体见 findAspectJAnnotationOnMethod
方法中的定义,在AspectJAdvisorFactory中讲过,该方法是由AbstractAspectJAdvisorFactory实现。
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 1. 查找当前方法上的通知,获取AspectJAnnotation对象,短路查找方式,查找到一个通知注解就封装返回,见后面分析
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 如果没有通知注解,则返回null
if (aspectJAnnotation == null) {
return null;
}
// 新建一个AspectJExpressionPointcut实例
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 设置expression表达式的值,也就是上面的通知注解的pointcut或者value属性的值
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
// 设置beanFactory
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
//返回该实例
return ajexp;
}
new InstantiationModelAwarePointcutAdvisorImpl
在 getAdvisor
代码块 4
中,将各参数进行封装成 InstantiationModelAwarePointcutAdvisorImpl
并返回。
我们来看一下它的构造方法:
public InstantiationModelAwarePointcutAdvisorImpl(
AspectJExpressionPointcut declaredPointcut, // 切入点
Method aspectJAdviceMethod, // 通知方法
AspectJAdvisorFactory aspectJAdvisorFactory, // ReflectiveAspectJAdvisorFactory工厂对象
MetadataAwareAspectInstanceFactory aspectInstanceFactory, // 切面类实例工厂,用于获取切面类实例单例(被封装的)
int declarationOrder, // 声明顺序,当前版本默认为0
String aspectName // 切面名,即beanName
) {
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;
// 1. 切面是否配置了懒加载,一般情况不设置,都走到else中
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 2. 如果是懒加载
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// 2.1 使其动态化:必须从预实例化状态变为后实例化状态。
// 如果它不是动态切入点,那么在第一次评估之后,Spring AOP基础设施可能会对其进行优化。
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// 3. 单例的切面类
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 3.1 实例化通知
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
instantiateAdvice()
在 new InstantiationModelAwarePointcutAdvisorImpl
的构造方法代码块的 3.1
中,将 Advisor
实例化为 Advice
通知。
实例化该通知器对应的 Advice
通知,通知实例用于执行通知方法的回调或者适配成拦截器。
这里要区别两种创建通知的过程:
- 在基于XML配置中,对应的通知是在解析XML标签时,通过构建bean定义的形式让Spring自动初始化。
- 而在基于注解中,是在
ReflectiveAspectJAdvisorFactory
中调用getAdvice
通过new
的方式手动创建Advice
并返回注入到InstantiationModelAwarePointcutAdvisorImpl
的instantiatedAdvice
属性中,具体逻辑见getAdvice
中。
// 空通知
private static final Advice EMPTY_ADVICE = new Advice() {};
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
// 1. 调用aspectJAdvisorFactory.getAdvice()手动创建Advice
Advice advice = this.aspectJAdvisorFactory.getAdvice(
this.aspectJAdviceMethod,
pointcut,
this.aspectInstanceFactory,
this.declarationOrder,
this.aspectName
);
return (advice != null ? advice : EMPTY_ADVICE);
}
getAdvice()
在 instantiateAdvice
代码块 1
中。
该方法在 ReflectiveAspectJAdvisorFactory
中实现,用于为给定的 AspectJ
通知方法构建一个 Advice
通知实例,通知实例用于执行通知方法的回调或者适配成拦截器。
@Override
@Nullable
public Advice getAdvice(
Method candidateAdviceMethod, // 通知方法
AspectJExpressionPointcut expressionPointcut, // 切入点
MetadataAwareAspectInstanceFactory aspectInstanceFactory, // 切面类实例工厂,用于获取切面类实例单例(封装过的)
int declarationOrder, // 声明顺序,目前版本默认为0
String aspectName // 切面名,即容器中的beanName
) {
// 获取切面类类型class
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 再再一次校验切面类
validate(candidateAspectClass);
// 查找AspectJ注解,找到一个就返回
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 如果当前类不是被@AspectJ注解标注的切面类,但是有存在AspectJ注解的方法,则抛出异常
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);
}
// 获取AspectJ注解的类型
AbstractAspectJAdvice springAdvice;
// 匹配枚举类型并创建对应类型的通知,一共有六种
switch (aspectJAnnotation.getAnnotationType()) {
// 如果是切入点注解,即@Pointcut
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
// 那么直接返回null,因为这里需要的是通知注解
return null;
// 如果是环绕通知注解,即@Around
case AtAround:
// 新建AspectJAroundAdvice类型的通知
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 如果是前置通知注解,即@Before
case AtBefore:
// 新建AspectJMethodBeforeAdvice类型的通知
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 如果是最终通知注解,即@After
case AtAfter:
// 新建AspectJAfterAdvice类型的通知
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 如果是后置通知注解,即@AfterReturning
case AtAfterReturning:
// 新建AspectJAfterReturningAdvice类型的通知
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
// 获取@AfterReturning注解
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
// 如果注解设置了returning属性,表示需要传递方法返回值参数,那么设置后置通知的returningName属性
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
// 如果是异常通知注解,即@AfterThrowing
case AtAfterThrowing:
// 新建AspectJAfterThrowingAdvice类型的通知
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
// 获取@AfterThrowing注解
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
// 如果注解设置了throwing属性,表示需要传递方法异常参数,那么设置异常通知的throwingName属性
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
// 其他情况不属于这几种类型的注解,则抛出异常
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// 配置通知
// 配置通知
springAdvice.setAspectName(aspectName);
// 设置declarationOrder,当前版本默认为0
springAdvice.setDeclarationOrder(declarationOrder);
// 通过参数名称发现器获取传递的参数,实际上就是获取通知注解上的argNames属性值,并且根据","进行拆分
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
/* 设置给argumentNames属性,并且可能会补充第一个参数名
如果第一个参数是JoinPoint.class || ProceedingJoinPoint.class || JoinPoint.StaticPart.class
会设置第一个参数名为 "THIS_JOIN_POINT"
*/
springAdvice.setArgumentNamesFromStringArray(argNames);
}
// 辅助参数绑定,后面执行invoke拦截器的时候就不会再绑定了
springAdvice.calculateArgumentBindings();
// 返回通知
return springAdvice;
}
getDeclareParentsAdvisor()
在 getAdvisors
代码块 6.1
中,用于获取引介增强通知器。
在解析引介增强字段时,调用该方法根据给定的成员变量字段创建一个 DeclareParentsAdvisor
引介增强通知器,如果没有 @DeclareParents
注解则返回null。
@Nullable
private Advisor getDeclareParentsAdvisor(Field introductionField) {
// 获取成员变量上的@DeclareParents注解
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
// 如果没有@DeclareParents注解,说明是普通变量,返回null
if (declareParents == null) {
// Not an introduction field
return null;
}
// 如果注解的defaultImpl属性值为默认值(默认值就是DeclareParents.class),则抛出异常
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}
// 解析@DeclareParents注解,返回DeclareParentsAdvisor通知器
return new DeclareParentsAdvisor(
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}
@EnableAspectJAutoProxy 注解解析
前面讲了通过XML文件的 <aop:aspectj-autoproxy />
标签开启Spring AOP配置。
我们也可以通过 @EnableAspectJAutoProxy
注解来代替 <aop:aspectj-autoproxy />
标签,这才是目前Spring AOP的主流配置。
@EnableAspectJAutoProxy
注解通常标注在配置类上,这样在容器启动的时候就能解析这个注解。
@EnableAspectJAutoProxy
注解上也包括了 proxyTargetClass
和 exposeProxy
属性的配置。
我们主要关注 @Import(AspectJAutoProxyRegistrar.class)
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 通过Import注解注入AspectJAutoProxyRegistrar的bean定义
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 表示是否强制采用CGLIB创建代理对象
* 默认值为false,表示首先尝试采用基于 Java 接口的代理,不行再采用CGLIB的代理
* 手动设置为true,表示强制创建基于子类的代理,即采用CGLIB代理
*/
boolean proxyTargetClass() default false;
/**
* 用于暴露代理对象,主要用来解决同一个目标类的方法互相调用时代理不生效的问题
* 默认值为false表示不开启
* 设置为true表示开启,那么就可以在被代理方法中通过AopContext.currentProxy()获取当前代理类对象
*/
boolean exposeProxy() default false;
}
@Import注解就是在ConfigurationClassPostProcessor后置处理器中被解析的,它的作用是引入bean定义。
AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar
继承自 ImportBeanDefinitionRegistrar
接口,实现了 ImportBeanDefinitionRegistrar
接口的class,该class对应的类本身不会被注册为bean定义,但是它的 registerBeanDefinitions
方法可用于自定义注册bean定义,并且该方法会被在处理过程中自动调用。registerBeanDefinitions
方法将会在 ConfigurationClassPostProcessor
的 postProcessBeanDefinitionRegistry
扩展回调方法中被调用。
其中它的 registerBeanDefinitions
方法主要作用是注册、配置一个AnnotationAwareAspectJAutoProxyCreator类型的自动代理创建者。
关于
ImportBeanDefinitionRegistrar
的内容在后面整理吧…这部分参考一下其他文章。SpringBoot2 | BeanDefinition 注册核心类 ImportBeanDefinitionRegistrar 源码分析 (十)
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 尝试注册或者升级一个名为"org.springframework.aop.config.internalAutoProxyCreator"
// 类型为AnnotationAwareAspectJAutoProxyCreator的自动代理创建者的bean定义
// 这个在前面讲过
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 解析@EnableAspectJAutoProxy注解的两个属性,配置自动代理创建者
// 获取@EnableAspectJAutoProxy注解的属性集合
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
// 如果设置了proxyTargetClass属性为true
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
// 如果设置了proxyTargetClass属性为true
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 如果设置了exposeProxy属性为true
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
// 如果设置了exposeProxy属性为true
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}