前面的文章介绍了 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。
java">// 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 标签子节点
配置自动代理生成器
java">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
java">// 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 标签对应一个 AspectJExpressionPointcutpointcutDefinition = 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
java">// ConfigBeanDefinitionParser
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {// advisor --> BeanDefinitionAbstractBeanDefinition 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));}// orderif (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
java">// 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-parentsList<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 注册到 BeanFactoryAbstractBeanDefinition 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 --> BeanDefinitionRootBeanDefinition 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 --> BeanDefinitionAbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences);// configure the advisor// 配置 advisor,一个 advice 对应一个 advisorRootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);advisorDefinition.setSource(parserContext.extractSource(adviceElement));advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);// advisor orderif (aspectElement.hasAttribute(ORDER_PROPERTY)) {advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));}// register the final advisor// 注册 advisorparserContext.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 的实例化。
java">// AbstractAdvisorAutoProxyCreator
@Override
public void setBeanFactory(BeanFactory beanFactory) {// 父类 AbstractAutoProxyCreatorsuper.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 是否需要代理。
java">@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 方法。
java">@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {// 获取所有候选 AdvisorList<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 这个方法。
java">// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findCandidateAdvisors() {Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");return this.advisorRetrievalHelper.findAdvisorBeans();
}
在 AspectJAwareAdvisorAutoProxyCreator 实例对象创建时,已经完成了 advisorRetrievalHelper 的创建赋值,是一个工具类 BeanFactoryAdvisorRetrievalHelper。
java">// 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。
java">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 的创建。
java">// 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 对象初始化时,完成目标通知方法的确定。
java">// 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 获取真正的对象。
java">// 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 的实例化。
java">public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;this.pointcut = advice.buildSafePointcut();
}
在构造方法中执行了 advice.buildSafePointcut(),这是在做什么呢?继续向下看。
java">// AbstractAspectJAdvice
public final Pointcut buildSafePointcut() {// AspectJExpressionPointcutPointcut 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。
java">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。
java">// 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 processedcontinue;}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 对此方法进行了重写。
java">@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 requiredif (!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。
java">// 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);// trueif (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader 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 方法。
java">// 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。
java">// AspectJExpressionPointcut
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {obtainPointcutExpression();// org.aspectj.weaver.tools.ShadowMatchShadowMatch 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 caseif (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 这个框架去实现。