spring 中 AspectJ 基于 XML 的实现分析
前面的文章介绍了 spring 引入 AspectJ 之后,基于注解实现 AOP 的过程分析,今天我们来看下AspectJ 基于 XML 的 AOP 实现逻辑。
XML 的实现示例可以参考 AspectJ 对于 AOP 的实现。
aop:config 标签解析
先去 spring-aop 模块下,META-INF/spring.handlers 中查看 aop 命名空间对应的处理器为 AopNamespaceHandler。在 AopNamespaceHandler#init 方法中发现为 config 标签注册的解析器为 org.springframework.aop.config.ConfigBeanDefinitionParser。
// ConfigBeanDefinitionParser
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 配置自动代理生成器
configureAutoProxyCreator(parserContext, element);
// 解析 aop:config 子节点
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
主要逻辑如下:
- 配置自动代理生成器
- 解析 aop:config 标签子节点
配置自动代理生成器
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 处理 proxy-target-class 和 expose-proxy 两个属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
其实就是在 BeanFactory 中注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition,如果 aop:config 设置了 proxy-target-class 和 expose-proxy 两个属性,则为这个注册的 BeanDefinition 也设置这两个属性,添加 proxyTargetClass 和 exposeProxy 到 propertyValues 中,供 bean 对象创建时使用。
解析 config 标签子节点
aop:config 共支持三种类型的子节点。分别如下:
- pointcut 定义切入点,配置切入点表达式
- advisor 自定义 Advisor,需要一个 Advice
- aspect 需对应一个切面类
在 ConfigBeanDefinitionParser#parse 中定义了三个分支分别解析对应的子节点 。
pointcut
// ConfigBeanDefinitionParser
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
// 获取 pointcut 标签 id 和 expression 两个属性
String id = pointcutElement.getAttribute(ID);
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
// 一个 pointcut 标签对应一个 AspectJExpressionPointcut
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
// 将配置 id 作为 beanName,注册创建的 BeanDefinition,不存在 id,会生成一个 beanName 之后,进行注册
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
// 创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
解析 pointcut 标签目的,就是创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition 进行注册。我们知道,AspectJExpressionPointcut 是连接 spring 和 AspectJ 的桥梁,必须需要一个切入点表达式,所以可以看到为注册的 BeanDefinition 设置了一个 expression 属性。
advisor
// ConfigBeanDefinitionParser
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// advisor --> BeanDefinition
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
// 注册
String advisorBeanName = id;
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// 解析 advisor 标签下的 pointcut 属性,为 advisorDef 设置属性
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
else if (pointcut instanceof String) {
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
this.parseState.pop();
}
}
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
// advice-ref,必须存在,不存在报错
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
// order
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
@Nullable
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
// pointcut 和 pointcut-ref 只能存在一个
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
else if (element.hasAttribute(POINTCUT)) {
// pointcut 直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式
String expression = element.getAttribute(POINTCUT);
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
return pointcutDefinition;
}
else if (element.hasAttribute(POINTCUT_REF)) {
String pointcutRef = element.getAttribute(POINTCUT_REF);
if (!StringUtils.hasText(pointcutRef)) {
parserContext.getReaderContext().error(
"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
return pointcutRef;
}
else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
}
创建 beanClass 为 DefaultBeanFactoryPointcutAdvisor 的 BeanDefinition,之后解析 advice-ref、pointcut/pointcut-ref、order 等属性,设置 propertyValues,完成 BeanDefinition 的注册。
aspect
// ConfigBeanDefinitionParser
private void parseAspect(Element aspectElement, ParserContext parserContext) {
// 获取 id 和 ref 属性
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
// 处理子标签 declare-parents
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
// 遍历子节点
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
// 判断是否是通知节点,只有是通知节点才处理
if (isAdviceNode(node, parserContext)) {
// 依赖的切面类只处理一次
if (!adviceFoundAlready) {
adviceFoundAlready = true;
// 必须存在切面类,不存在报错
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
// 作为依赖的 bean 存在
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 一个通知标签封装一个 Advisor,之后将这个 Advisor 对应的 BeanDefinition 注册到 BeanFactory
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
// aop:aspect 下 pointcut 子标签,作用和 aop:config 标签下 pointcut 子标签一致
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
// 是 advice 节点,五种通知对应五个标签
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
if (!(aNode instanceof Element)) {
return false;
}
else {
String name = parserContext.getDelegate().getLocalName(aNode);
return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
}
}
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
// method --> BeanDefinition
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
// 切面实例工厂
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
// 封装通知 advice --> BeanDefinition
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
// 配置 advisor,一个 advice 对应一个 advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
// advisor order
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
// 注册 advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
// AspectJ 一种通知类型适配 spring 中一种通知类型
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
// 添加属性
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
// 构造参数,每一个 AspectJXXXAdvice 构造方法都需要三个参数
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
// 切点
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
// 切面实例工厂
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
// 前置通知
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
this.pointcut = advice.buildSafePointcut();
}
其实就是解析各种通知标签,之后封装 BeanDefinition,注册到 BeanFactory。一个通知对应一个 Advisor。
完成这些标签解析之后,也就在 BeanFactory 中注册了所有的 Advisor。
自动代理生成器的实例化
在 AbstractApplicationContext#refresh 中执行 registerBeanPostProcessors 时,完成 AspectJAwareAdvisorAutoProxyCreator 的实例化。
// AbstractAdvisorAutoProxyCreator
@Override
public void setBeanFactory(BeanFactory beanFactory) {
// 父类 AbstractAutoProxyCreator
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 初始化赋值
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
在初始化时,进行了相关字段的赋值。
AspectJAwareAdvisorAutoProxyCreator 继承 AbstractAutoProxyCreator,所以代理的生成也遵循 spring 中定义的逻辑。
至于前面解析的各种标签注册的 BeanDefinition,则在 AbstractApplicationContext#finishBeanFactoryInitialization 时完成实例对象的创建。
代理的实现
BeanFactory 中所有 Advisor 的实例化
在业务 bean 的实例化过程中,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,就会执行到 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法中,判断业务 bean 是否需要代理。
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
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;
}
}
// 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.
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;
}
其中,AspectJAwareAdvisorAutoProxyCreator 重写了 shouldSkip 方法。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 获取所有候选 Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// advisor 中 aspectName 如果和带创建的 beanName 一致,表明正在创建切面类实例,返回 true,表示切面类不需要代理
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
主要来看下 findCandidateAdvisors 这个方法。
// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
在 AspectJAwareAdvisorAutoProxyCreator 实例对象创建时,已经完成了 advisorRetrievalHelper 的创建赋值,是一个工具类 BeanFactoryAdvisorRetrievalHelper。
// BeanFactoryAdvisorRetrievalHelper
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 获取注册的所有 Advisor 对应的名称集合
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 对象未创建则在此时进行创建
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
...
// 抛出异常
}
}
}
}
return advisors;
}
bean 的创建过程,此处不再赘述。有几点需要注意:
- 一个 pointcut 可以被多个 advisor 和 aspect 下通知子标签引用,即可以在一个切入点应用多个顾问和通知,pointcut 对应的 beanClass 为 AspectJExpressionPointcut,创建 BeanDefinition 时设置 scope 为 prototype,所以每一个对 AspectJExpressionPointcut 的引用,都会创建一个新的对象。
- aspect 标签下各个通知子标签对应的 Advisor 为 AspectJPointcutAdvisor,持有的 Advice 为通知子标签封装的 AspectJXXXAdvice。
- AspectJPointcutAdvisor 构造方法注入时,需要 AbstractAspectJAdvice,而每一个 AspectJXXXAdvice 构造方法都需要三个参数,传递给父类 AbstractAspectJAdvice。
public AbstractAspectJAdvice(
Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.pointcut = pointcut;
this.aspectInstanceFactory = aspectInstanceFactory;
}
第一个参数,需要的是一个切面类中的通知方法,在 aspect 标签解析时,针对通知标签,封装一个 beanClass 为 MethodLocatingFactoryBean 的 BeanDefinition。当解析第一个参数时,会执行 MethodLocatingFactoryBean 的创建。
// MethodLocatingFactoryBean
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!StringUtils.hasText(this.targetBeanName)) {
throw new IllegalArgumentException("Property 'targetBeanName' is required");
}
if (!StringUtils.hasText(this.methodName)) {
throw new IllegalArgumentException("Property 'methodName' is required");
}
Class<?> beanClass = beanFactory.getType(this.targetBeanName);
if (beanClass == null) {
throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
}
this.method = BeanUtils.resolveSignature(this.methodName, beanClass);
if (this.method == null) {
throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
"] on bean [" + this.targetBeanName + "]");
}
}
会在 MethodLocatingFactoryBean 对象初始化时,完成目标通知方法的确定。
// BeanUtils 根据方法名称从指定 clazz 中确定 method
@Nullable
public static Method resolveSignature(String signature, Class<?> clazz) {
Assert.hasText(signature, "'signature' must not be empty");
Assert.notNull(clazz, "Class must not be null");
int startParen = signature.indexOf('(');
int endParen = signature.indexOf(')');
if (startParen > -1 && endParen == -1) {
throw new IllegalArgumentException("Invalid method signature '" + signature +
"': expected closing ')' for args list");
}
else if (startParen == -1 && endParen > -1) {
throw new IllegalArgumentException("Invalid method signature '" + signature +
"': expected opening '(' for args list");
}
else if (startParen == -1) {
// 不指定参数类型
return findMethodWithMinimalParameters(clazz, signature);
}
else {
// 方法名
String methodName = signature.substring(0, startParen);
// 逗号分割,获取参数类型数组
String[] parameterTypeNames =
StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
for (int i = 0; i < parameterTypeNames.length; i++) {
String parameterTypeName = parameterTypeNames[i].trim();
try {
// 加载类型,保证配置的每一个类型的正确性
parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
}
catch (Throwable ex) {
throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
}
}
// 根据类型获取指定方法
return findMethod(clazz, methodName, parameterTypes);
}
}
@Nullable
public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
throws IllegalArgumentException {
// 实际上 clazz.getMethods() 已经包含了当前类及所有父类中 public、protected 修饰的方法,但不包含 private 方法
Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
if (targetMethod == null) {
// 当目标方法为 private 修饰时,通过以下方法查找
targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
}
return targetMethod;
}
@Nullable
public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
throws IllegalArgumentException {
Method targetMethod = null;
int numMethodsFoundWithCurrentMinimumArgs = 0;
for (Method method : methods) {
// 比较参数名称
if (method.getName().equals(methodName)) {
int numParams = method.getParameterCount();
// 将参数长度最短的方法作为 targetMethod 返回
if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
targetMethod = method;
numMethodsFoundWithCurrentMinimumArgs = 1;
}
else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
// 用常规方法覆盖桥接方法
if (targetMethod.isBridge()) {
// Prefer regular method over bridge...
targetMethod = method;
}
else {
// Additional candidate with same length
// 当存在方法重写或重载时,发现了两个名称和参数长度一样的方法,数量自增
numMethodsFoundWithCurrentMinimumArgs++;
}
}
}
}
// 存在方法重写时抛出异常,即不确定使用的是子类方法还是父类方法
// 重载时也会存在,方法名称一致,参数长度一致,但类型不一致,此处只校验长度,无法确定是哪一个方法
if (numMethodsFoundWithCurrentMinimumArgs > 1) {
throw new IllegalArgumentException("Cannot resolve method '" + methodName +
"' to a unique method. Attempted to resolve to overloaded method with " +
"the least number of parameters but there were " +
numMethodsFoundWithCurrentMinimumArgs + " candidates.");
}
return targetMethod;
}
// 查找当前类,并递归父类,返回 public、protected、private 修饰方法
@Nullable
public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)
throws IllegalArgumentException {
Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
if (targetMethod == null && clazz.getSuperclass() != null) {
targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
}
return targetMethod;
}
@Nullable
public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
try {
return clazz.getMethod(methodName, paramTypes);
}
catch (NoSuchMethodException ex) {
return findDeclaredMethod(clazz, methodName, paramTypes);
}
}
上面的代码解释了在切面类中确定目标通知方法的实现,主要逻辑如下:
- 不指定方法参数类型时,按最短参数长度查找,指定参数类型时,按参数类型查找,也就是说,xml 中配置 methodName 时,可以是 methodName(argType1,argType2) 这种配置原型。
- 不指定方法参数类型时,按最短参数长度查找,若存在方法重写和方法重载导致的多个方法名称和参数长度一致,会抛出异常
- private 修饰的方法也可以被找到而作为目标通知方法
MethodLocatingFactoryBean 创建完成之后,由于是 FactoryBean 子类,会调用 this.beanFactory.getObjectFromFactoryBean 获取真正的对象。
// MethodLocatingFactoryBean
@Override
@Nullable
public Method getObject() throws Exception {
return this.method;
}
可以看到,获取的 Method 对象就是上面在切面类中确定的方法。这也解释了为什么 AspectJXXXAdvice 构造方法第一个参数类型为 Method,而解析标签时却配置了一个 MethodLocatingFactoryBean 工厂。
接下来看第二个构造参数,需要的是一个 AspectJExpressionPointcut,通知子标签支持 pointcut 和 pointcut-ref 两种方式来定义切入点。
解析标签时,如果是 pointcut,直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式字符串;如果是 pointcut-ref,表明是一个引用类型,引用的 aop:pointcut 子标签已经封装成了 BeanDefinition,此处返回名称字符串封装一个 RuntimeBeanReference。所以传递给第二个构造参数的,要么是一个 BeanDefinition,要么是一个 RuntimeBeanReference。
在 ConstructorResolver#resolveConstructorArguments 方法中,解析构造参数,不管是 BeanDefinition,还是 RuntimeBeanReference 引用,由于背后定义 BeanDefinition 时设置的 scope 都是 prototype,所以此处都会创建一个新的对象。
第三个参数,需要一个 AspectInstanceFactory,即切面实例工厂,传入的是一个 beanClass 为 SimpleBeanFactoryAwareAspectInstanceFactory 的 BeanDefinition,而这个 SimpleBeanFactoryAwareAspectInstanceFactory 就是 AspectInstanceFactory 的实现类,在此时完成实例化对象创建。
事实上,aspect 下的通知子标签,一个通知对应一个 Advisor,即 AspectJPointcutAdvisor,由于存在构造参数,采用构造方法实例化,此时又对依赖的构造参数 AbstractAspectJAdvice 进行了实例化创建,这个 AbstractAspectJAdvice 又存在构造参数,继续采用 AbstractAutowireCapableBeanFactory#autowireConstructor 进行实例化对象创建。
创建完 AspectJXXXAdvice,将其作为构造参数,完成 AspectJPointcutAdvisor 的实例化。
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
this.pointcut = advice.buildSafePointcut();
}
在构造方法中执行了 advice.buildSafePointcut(),这是在做什么呢?继续向下看。
// AbstractAspectJAdvice
public final Pointcut buildSafePointcut() {
// AspectJExpressionPointcut
Pointcut pc = getPointcut();
MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
// 组合
return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
}
// AspectJExpressionPointcut
@Override
public MethodMatcher getMethodMatcher() {
obtainPointcutExpression();
return this;
}
// AspectJExpressionPointcut
private PointcutExpression obtainPointcutExpression() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
// 解析切入点表达式,创建 PointcutExpressionImpl 返回
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
}
public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
super(mm1, mm2);
}
pc.getMethodMatcher() 时完成了 pc 中切入点表达式的解析,创建了一个 org.aspectj.internal.lang.reflect.PointcutExpressionImpl 对象赋值给 AspectJExpressionPointcut 中的 pointcutExpression 字段。之后创建一个 IntersectionIntroductionAwareMethodMatcher 对象作为 safeMethodMatcher,之后将 safeMethodMatcher 和 pc.getClassFilter() 返回的 AspectJExpressionPointcut 组合起来,封装一个 ComposablePointcut 返回。
完成 AspectJPointcutAdvisor 的对象创建之后,将其加入 advisors 集合,之后将集合返回,作为候选的 Advisor,即 candidateAdvisors。
再回到 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法中,遍历 candidateAdvisors,advisor 中 aspectName 如果和当前创建的 beanName 一致,表明正在创建切面类实例,返回 true,即需要跳过。之后在 AbstractAutoProxyCreator#postProcessBeforeInstantiation 中,针对当前 beanClass 和 beanName 生成的 cacheKey,标记为 false。
代理对象的创建
完成目标类的实例化之后,在进行初始化时,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,会执行到 AbstractAutoProxyCreator#postProcessAfterInitialization --> wrapIfNecessary。
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.
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;
}
这是 spring 创建代理的模板。先来看对 Advisor 的过滤,找到当前目标类需要的 Advisor。
// AbstractAdvisorAutoProxyCreator
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有 BeanFaactory 中定义的 Advisor,前面创建过,所以此处获取很快
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 扩展
extendAdvisors(eligibleAdvisors);
// 排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// AopUtils
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
// 对于 Advisor 为 DefaultBeanFactoryPointcutAdvisor,在进行 canApply 时执行 pc.getClassFilter 完成切入点表达式的解析
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
这些都是 spring 中实现 AOP 的通用代码,区别就在于不同的 org.springframework.aop.PointcutAdvisor,持有的 org.springframework.aop.Pointcut 不同,不同的 org.springframework.aop.Pointcut,持有的 ClassFilter 和 MethodMatcher 不同。实现AopUtils#canApply 时,利用每个 org.springframework.aop.Pointcut 中 ClassFilter 和 MethodMatcher 中定义的 matches 方法进行匹配。所以也可以按照自己定义的规则,对 org.springframework.aop.Pointcut 进行扩展。
找到合格的 Advisor 之后,调用 AbstractAdvisorAutoProxyCreator#extendAdvisors,而 AspectJAwareAdvisorAutoProxyCreator 对此方法进行了重写。
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
判定是否 Advisor 集合中存在 AspectJAdvice,存在,在 Advisor 集合的首位加入 ExposeInvocationInterceptor.ADVISOR。至于为啥要加入这个 Advisor,可以参考 spring 中 AspectJ 基于注解的实现分析。
此处有一点要注意,就是如果 Advisor 为 DefaultBeanFactoryPointcutAdvisor,此前虽然进行了实例化,但其中依赖的 Advice 并未进行实例化,此时执行 advisor.getAdvice() 会对依赖的 Advice 完成实例化。
扩展完 eligibleAdvisors 之后,对 eligibleAdvisors 按照优先级进行排序。详细的排序过程可以参考AspectJ 下 Advisor 的排序过程。
排序之后,将集合处理成数组返回,赋值给 specificInterceptors。
之后调用 AbstractAutoProxyCreator#createProxy 创建代理,此时 AbstractAutoProxyCreator 就是 AspectJAwareAdvisorAutoProxyCreator,将 <aop:config> 标签中定义的 proxy-target-class 和 expose-proxy 两个属性又传递给 ProxyFactory。
// AbstractAutoProxyCreator
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
创建代理的这一步,都是遵循 spring 中的定义来实现。
方法调用
相同处理的,此处不在赘述,可以参考spring 中自动代理生成器的实现。
有一点需要注意,就是调用 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法时,遍历 advisors。前面介绍过,aspect 标签下通知对应的 Advisor 为 AspectJPointcutAdvisor,在执行有参构造时,封装的 pointcut 为 ComposablePointcut。
两个字段,主要关注 methodMatcher,通过前面的介绍,这个 methodMatcher 为 MethodMatchers$IntersectionIntroductionAwareMethodMatcher。 mm1 为定义的 AbstractAspectJAdvice$AdviceExcludingMethodMatcher,mm2 为 pc.getMethodMatcher(),也就是 Pointcut 中持有的 MethodMatcher。
此时调用 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 得到 MethodMatchers$IntersectionIntroductionAwareMethodMatcher,接着调用其 matches 方法。
// IntersectionIntroductionAwareMethodMatcher
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
}
// MethodMatches
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(mm, "MethodMatcher must not be null");
return (mm instanceof IntroductionAwareMethodMatcher ?
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
mm.matches(method, targetClass));
}
// AdviceExcludingMethodMatcher
@Override
public boolean matches(Method method, Class<?> targetClass) {
return !this.adviceMethod.equals(method);
}
AdviceExcludingMethodMatcher 并不是 IntroductionAwareMethodMatcher 实例,调用 AdviceExcludingMethodMatcher#matches 方法判定目标方法是否是通知方法,不是返回 true。所以主要的判断还是基于 mm2,mm2 为 AspectJExpressionPointcut。
// AspectJExpressionPointcut
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
obtainPointcutExpression();
// org.aspectj.weaver.tools.ShadowMatch
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
进入 AspectJExpressionPointcut#matches,委托给 AspectJ 进行切入点表达式和目标方法的匹配。
之后将筛选出的 Advisor,根据持有的通知类型的不同,适配成不同的 org.aopalliance.intercept.MethodInterceptor,封装成拦截器链。接着封装 MethodInvocation,调用 proceed 方法。
总结
介绍完了 AspectJ 下基于注解和 XML 的 AOP实现。现在我们来总结一下这两者的区别。
标签解析
实现方式 | 标签解析器 |
注解 | AspectJAutoProxyBeanDefinitionParser |
XML | ConfigBeanDefinitionParser |
代理生成器
实现方式 | 代理生成器 |
注解 | AnnotationAwareAspectJAutoProxyCreator |
XML | AspectJAwareAdvisorAutoProxyCreator |
Advisor 的创建
实现方式 | 代理生成器 |
注解 | AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors |
XML | AbstractAdvisorAutoProxyCreator#findCandidateAdvisors |
注解方式下,AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors 方法,通过找到持有 @Aspect 注解的类,接着获取类中定义的通知方法,将其封装成 Advisor。
而 XML 模式下,由于在 XML 中已经定义了切面类、切入点、通知和顾问,所以会采用 spring 中定义的通用模板来获取 Advisor。
Advisor 的类型
实现方式 | Advisor 类型 |
注解 | InstantiationModelAwarePointcutAdvisorImpl |
XML | advisor 标签对应 DefaultBeanFactoryPointcutAdvisor |
aspect 下通知子标签对应 AspectJPointcutAdvisor |
除了这些显式的不同,还有一个隐式的不同点,就是 AspectJ 解析 expression 的时机。
实现方式 | Advisor 类型 | AspectJ 解析 expression 的时机 |
注解 | InstantiationModelAwarePointcutAdvisorImpl | AbstractAdvisorAutoProxyCreator下findEligibleAdvisors 方法中对获取的 candidateAdvisors 进行筛选时完成 |
XML | DefaultBeanFactoryPointcutAdvisor | |
AspectJPointcutAdvisor | 有参构造方法实例化,执行 buildSafePointcut 方法时完成 |
下面我们来看下注解和 XML 这两种实现方式的共同点。
Advisor 的创建时机,都是在执行 AbstractAutoProxyCreator#postProcessBeforeInstantiation ,第一次调用 shouldSkip 方法时完成的,并将创建的 Advisor 实例对象加入到了 DefaultListableBeanFactory 的父类 DefaultSingletonBeanRegistry 中的 singletonObjects,之后获取 Advisor 时直接从 singletonObjects 获取。
业务 bean 代理对象的创建和方法调用,完全遵从 spring 中定义的 AOP 实现。至于方法匹配,则通过 AspectJExpressionPointcut 这个纽带,完全委托给了 AspectJ 这个框架去实现。