spring 中 AspectJ 基于 XML 的实现分析

打印 上一主题 下一主题

主题 1382|帖子 1382|积分 4146

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
前面的文章介绍了 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。
  1. // ConfigBeanDefinitionParser
  2. @Override
  3. @Nullable
  4. public BeanDefinition parse(Element element, ParserContext parserContext) {
  5.         CompositeComponentDefinition compositeDef =
  6.                         new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
  7.         parserContext.pushContainingComponent(compositeDef);
  8.         // 配置自动代理生成器
  9.         configureAutoProxyCreator(parserContext, element);
  10.         // 解析 aop:config 子节点
  11.         List<Element> childElts = DomUtils.getChildElements(element);
  12.         for (Element elt: childElts) {
  13.                 String localName = parserContext.getDelegate().getLocalName(elt);
  14.                 if (POINTCUT.equals(localName)) {
  15.                         parsePointcut(elt, parserContext);
  16.                 }
  17.                 else if (ADVISOR.equals(localName)) {
  18.                         parseAdvisor(elt, parserContext);
  19.                 }
  20.                 else if (ASPECT.equals(localName)) {
  21.                         parseAspect(elt, parserContext);
  22.                 }
  23.         }
  24.         parserContext.popAndRegisterContainingComponent();
  25.         return null;
  26. }
复制代码
主要逻辑如下:

  • 配置主动署理生成器
  • 解析 aop:config 标签子节点
配置主动署理生成器

  1. private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
  2.         AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
  3. }
  4. public static void registerAspectJAutoProxyCreatorIfNecessary(
  5.                 ParserContext parserContext, Element sourceElement) {
  6.         // 注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition
  7.         BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
  8.                         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
  9.         // 处理 proxy-target-class 和 expose-proxy 两个属性
  10.         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
  11.         registerComponentIfNecessary(beanDefinition, parserContext);
  12. }
  13. @Nullable
  14. public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
  15.                 BeanDefinitionRegistry registry, @Nullable Object source) {
  16.         return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
  17. }
复制代码
实在就是在 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

  1. // ConfigBeanDefinitionParser
  2. private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
  3.         // 获取 pointcut 标签 id 和 expression 两个属性
  4.         String id = pointcutElement.getAttribute(ID);
  5.         String expression = pointcutElement.getAttribute(EXPRESSION);
  6.         AbstractBeanDefinition pointcutDefinition = null;
  7.         try {
  8.                 this.parseState.push(new PointcutEntry(id));
  9.                 // 一个 pointcut 标签对应一个 AspectJExpressionPointcut
  10.                 pointcutDefinition = createPointcutDefinition(expression);
  11.                 pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
  12.                 // 将配置 id 作为 beanName,注册创建的 BeanDefinition,不存在 id,会生成一个 beanName 之后,进行注册
  13.                 String pointcutBeanName = id;
  14.                 if (StringUtils.hasText(pointcutBeanName)) {
  15.                         parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
  16.                 }
  17.                 else {
  18.                         pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
  19.                 }
  20.                 parserContext.registerComponent(
  21.                                 new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
  22.         }
  23.         finally {
  24.                 this.parseState.pop();
  25.         }
  26.         return pointcutDefinition;
  27. }
  28. // 创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition
  29. protected AbstractBeanDefinition createPointcutDefinition(String expression) {
  30.         RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
  31.         beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
  32.         beanDefinition.setSynthetic(true);
  33.         beanDefinition.getPropertyValues().add(EXPRESSION, expression);
  34.         return beanDefinition;
  35. }
复制代码
解析 pointcut 标签目的,就是创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition 进行注册。我们知道,AspectJExpressionPointcut 是连接 spring 和 AspectJ 的桥梁,必须需要一个切入点表达式,以是可以看到为注册的 BeanDefinition 设置了一个 expression 属性。
advisor

  1. // ConfigBeanDefinitionParser
  2. private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
  3.         // advisor --> BeanDefinition
  4.         AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
  5.         String id = advisorElement.getAttribute(ID);
  6.         try {
  7.                 this.parseState.push(new AdvisorEntry(id));
  8.                 // 注册
  9.                 String advisorBeanName = id;
  10.                 if (StringUtils.hasText(advisorBeanName)) {
  11.                         parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
  12.                 }
  13.                 else {
  14.                         advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
  15.                 }
  16.                
  17.                 // 解析 advisor 标签下的 pointcut 属性,为 advisorDef 设置属性
  18.                 Object pointcut = parsePointcutProperty(advisorElement, parserContext);
  19.                 if (pointcut instanceof BeanDefinition) {
  20.                         advisorDef.getPropertyValues().add(POINTCUT, pointcut);
  21.                         parserContext.registerComponent(
  22.                                         new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
  23.                 }
  24.                 else if (pointcut instanceof String) {
  25.                         advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
  26.                         parserContext.registerComponent(
  27.                                         new AdvisorComponentDefinition(advisorBeanName, advisorDef));
  28.                 }
  29.         }
  30.         finally {
  31.                 this.parseState.pop();
  32.         }
  33. }
  34. private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
  35.         RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
  36.         advisorDefinition.setSource(parserContext.extractSource(advisorElement));
  37.         // advice-ref,必须存在,不存在报错
  38.         String adviceRef = advisorElement.getAttribute(ADVICE_REF);
  39.         if (!StringUtils.hasText(adviceRef)) {
  40.                 parserContext.getReaderContext().error(
  41.                                 "'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
  42.         }
  43.         else {
  44.                 advisorDefinition.getPropertyValues().add(
  45.                                 ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
  46.         }
  47.         // order
  48.         if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
  49.                 advisorDefinition.getPropertyValues().add(
  50.                                 ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
  51.         }
  52.         return advisorDefinition;
  53. }
  54. @Nullable
  55. private Object parsePointcutProperty(Element element, ParserContext parserContext) {
  56.         // pointcut 和 pointcut-ref 只能存在一个
  57.         if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
  58.                 parserContext.getReaderContext().error(
  59.                                 "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
  60.                                 element, this.parseState.snapshot());
  61.                 return null;
  62.         }
  63.         else if (element.hasAttribute(POINTCUT)) {
  64.                 // pointcut 直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式
  65.                 String expression = element.getAttribute(POINTCUT);
  66.                 AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
  67.                 pointcutDefinition.setSource(parserContext.extractSource(element));
  68.                 return pointcutDefinition;
  69.         }
  70.         else if (element.hasAttribute(POINTCUT_REF)) {
  71.                 String pointcutRef = element.getAttribute(POINTCUT_REF);
  72.                 if (!StringUtils.hasText(pointcutRef)) {
  73.                         parserContext.getReaderContext().error(
  74.                                         "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
  75.                         return null;
  76.                 }
  77.                 return pointcutRef;
  78.         }
  79.         else {
  80.                 parserContext.getReaderContext().error(
  81.                                 "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
  82.                                 element, this.parseState.snapshot());
  83.                 return null;
  84.         }
  85. }
复制代码
创建 beanClass 为 DefaultBeanFactoryPointcutAdvisor 的 BeanDefinition,之后解析 advice-ref、pointcut/pointcut-ref、order 等属性,设置 propertyValues,完成 BeanDefinition 的注册。
aspect

  1. // ConfigBeanDefinitionParser
  2. private void parseAspect(Element aspectElement, ParserContext parserContext) {
  3.         // 获取 id 和 ref 属性
  4.         String aspectId = aspectElement.getAttribute(ID);
  5.         String aspectName = aspectElement.getAttribute(REF);
  6.         try {
  7.                 this.parseState.push(new AspectEntry(aspectId, aspectName));
  8.                 List<BeanDefinition> beanDefinitions = new ArrayList<>();
  9.                 List<BeanReference> beanReferences = new ArrayList<>();
  10.                 // 处理子标签 declare-parents
  11.                 List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
  12.                 for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
  13.                         Element declareParentsElement = declareParents.get(i);
  14.                         beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
  15.                 }
  16.                 // We have to parse "advice" and all the advice kinds in one loop, to get the
  17.                 // ordering semantics right.
  18.                 NodeList nodeList = aspectElement.getChildNodes();
  19.                 boolean adviceFoundAlready = false;
  20.                 // 遍历子节点
  21.                 for (int i = 0; i < nodeList.getLength(); i++) {
  22.                         Node node = nodeList.item(i);
  23.                         // 判断是否是通知节点,只有是通知节点才处理
  24.                         if (isAdviceNode(node, parserContext)) {
  25.                                 // 依赖的切面类只处理一次
  26.                                 if (!adviceFoundAlready) {
  27.                                         adviceFoundAlready = true;
  28.                                         // 必须存在切面类,不存在报错
  29.                                         if (!StringUtils.hasText(aspectName)) {
  30.                                                 parserContext.getReaderContext().error(
  31.                                                                 "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
  32.                                                                 aspectElement, this.parseState.snapshot());
  33.                                                 return;
  34.                                         }
  35.                                         // 作为依赖的 bean 存在
  36.                                         beanReferences.add(new RuntimeBeanReference(aspectName));
  37.                                 }
  38.                                 // 一个通知标签封装一个 Advisor,之后将这个 Advisor 对应的 BeanDefinition 注册到 BeanFactory
  39.                                 AbstractBeanDefinition advisorDefinition = parseAdvice(
  40.                                                 aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
  41.                                 beanDefinitions.add(advisorDefinition);
  42.                         }
  43.                 }
  44.                 AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
  45.                                 aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
  46.                 parserContext.pushContainingComponent(aspectComponentDefinition);
  47.                 // aop:aspect 下 pointcut 子标签,作用和 aop:config 标签下 pointcut 子标签一致
  48.                 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
  49.                 for (Element pointcutElement : pointcuts) {
  50.                         parsePointcut(pointcutElement, parserContext);
  51.                 }
  52.                 parserContext.popAndRegisterContainingComponent();
  53.         }
  54.         finally {
  55.                 this.parseState.pop();
  56.         }
  57. }
  58. // 是 advice 节点,五种通知对应五个标签
  59. private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
  60.         if (!(aNode instanceof Element)) {
  61.                 return false;
  62.         }
  63.         else {
  64.                 String name = parserContext.getDelegate().getLocalName(aNode);
  65.                 return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
  66.                                 AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
  67.         }
  68. }
  69. private AbstractBeanDefinition parseAdvice(
  70.                 String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
  71.                 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
  72.         try {
  73.                 this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
  74.                 // create the method factory bean
  75.                 // method --> BeanDefinition
  76.                 RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
  77.                 methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
  78.                 methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
  79.                 methodDefinition.setSynthetic(true);
  80.                 // create instance factory definition
  81.                 // 切面实例工厂
  82.                 RootBeanDefinition aspectFactoryDef =
  83.                                 new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
  84.                 aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
  85.                 aspectFactoryDef.setSynthetic(true);
  86.                 // register the pointcut
  87.                 // 封装通知 advice --> BeanDefinition
  88.                 AbstractBeanDefinition adviceDef = createAdviceDefinition(
  89.                                 adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
  90.                                 beanDefinitions, beanReferences);
  91.                 // configure the advisor
  92.                 // 配置 advisor,一个 advice 对应一个 advisor
  93.                 RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
  94.                 advisorDefinition.setSource(parserContext.extractSource(adviceElement));
  95.                 advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
  96.                 // advisor order
  97.                 if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
  98.                         advisorDefinition.getPropertyValues().add(
  99.                                         ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
  100.                 }
  101.                 // register the final advisor
  102.                 // 注册 advisor
  103.                 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
  104.                 return advisorDefinition;
  105.         }
  106.         finally {
  107.                 this.parseState.pop();
  108.         }
  109. }
  110. private AbstractBeanDefinition createAdviceDefinition(
  111.                 Element adviceElement, ParserContext parserContext, String aspectName, int order,
  112.                 RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
  113.                 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
  114.         // AspectJ 一种通知类型适配 spring 中一种通知类型
  115.         RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
  116.         adviceDefinition.setSource(parserContext.extractSource(adviceElement));
  117.         // 添加属性
  118.         adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
  119.         adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
  120.         if (adviceElement.hasAttribute(RETURNING)) {
  121.                 adviceDefinition.getPropertyValues().add(
  122.                                 RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
  123.         }
  124.         if (adviceElement.hasAttribute(THROWING)) {
  125.                 adviceDefinition.getPropertyValues().add(
  126.                                 THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
  127.         }
  128.         if (adviceElement.hasAttribute(ARG_NAMES)) {
  129.                 adviceDefinition.getPropertyValues().add(
  130.                                 ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
  131.         }
  132.         // 构造参数,每一个 AspectJXXXAdvice 构造方法都需要三个参数
  133.         ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
  134.         cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
  135.         // 切点
  136.         Object pointcut = parsePointcutProperty(adviceElement, parserContext);
  137.         if (pointcut instanceof BeanDefinition) {
  138.                 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
  139.                 beanDefinitions.add((BeanDefinition) pointcut);
  140.         }
  141.         else if (pointcut instanceof String) {
  142.                 RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
  143.                 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
  144.                 beanReferences.add(pointcutRef);
  145.         }
  146.         // 切面实例工厂
  147.         cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
  148.         return adviceDefinition;
  149. }
  150. private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
  151.         String elementName = parserContext.getDelegate().getLocalName(adviceElement);
  152.         if (BEFORE.equals(elementName)) {
  153.                 return AspectJMethodBeforeAdvice.class;
  154.         }
  155.         else if (AFTER.equals(elementName)) {
  156.                 return AspectJAfterAdvice.class;
  157.         }
  158.         else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
  159.                 return AspectJAfterReturningAdvice.class;
  160.         }
  161.         else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
  162.                 return AspectJAfterThrowingAdvice.class;
  163.         }
  164.         else if (AROUND.equals(elementName)) {
  165.                 return AspectJAroundAdvice.class;
  166.         }
  167.         else {
  168.                 throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
  169.         }
  170. }
  171. // 前置通知
  172. public AspectJMethodBeforeAdvice(
  173.                 Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
  174.         super(aspectJBeforeAdviceMethod, pointcut, aif);
  175. }
  176. public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
  177.         Assert.notNull(advice, "Advice must not be null");
  178.         this.advice = advice;
  179.         this.pointcut = advice.buildSafePointcut();
  180. }
复制代码
实在就是解析各种通知标签,之后封装 BeanDefinition,注册到 BeanFactory。一个通知对应一个 Advisor。
完成这些标签解析之后,也就在 BeanFactory 中注册了所有的 Advisor。
主动署理生成器的实例化

在 AbstractApplicationContext#refresh 中实行 registerBeanPostProcessors 时,完成 AspectJAwareAdvisorAutoProxyCreator 的实例化。
  1. // AbstractAdvisorAutoProxyCreator
  2. @Override
  3. public void setBeanFactory(BeanFactory beanFactory) {
  4.         // 父类 AbstractAutoProxyCreator
  5.         super.setBeanFactory(beanFactory);
  6.         if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
  7.                 throw new IllegalArgumentException(
  8.                                 "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
  9.         }
  10.         initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
  11. }
  12. protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  13.         // 初始化赋值
  14.         this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
  15. }
复制代码
在初始化时,进行了相关字段的赋值。

AspectJAwareAdvisorAutoProxyCreator 继续 AbstractAutoProxyCreator,以是署理的生成也遵照 spring 中定义的逻辑。
至于前面解析的各种标签注册的 BeanDefinition,则在 AbstractApplicationContext#finishBeanFactoryInitialization 时完成实例对象的创建。
署理的实现

BeanFactory 中所有 Advisor 的实例化

在业务 bean 的实例化过程中,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,就会实行到 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法中,判断业务 bean 是否需要署理。
  1. @Override
  2. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
  3.         Object cacheKey = getCacheKey(beanClass, beanName);
  4.         if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
  5.                 if (this.advisedBeans.containsKey(cacheKey)) {
  6.                         return null;
  7.                 }
  8.                 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
  9.                         this.advisedBeans.put(cacheKey, Boolean.FALSE);
  10.                         return null;
  11.                 }
  12.         }
  13.         // Create proxy here if we have a custom TargetSource.
  14.         // Suppresses unnecessary default instantiation of the target bean:
  15.         // The TargetSource will handle target instances in a custom fashion.
  16.         TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  17.         if (targetSource != null) {
  18.                 if (StringUtils.hasLength(beanName)) {
  19.                         this.targetSourcedBeans.add(beanName);
  20.                 }
  21.                 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
  22.                 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
  23.                 this.proxyTypes.put(cacheKey, proxy.getClass());
  24.                 return proxy;
  25.         }
  26.         return null;
  27. }
复制代码
其中,AspectJAwareAdvisorAutoProxyCreator 重写了 shouldSkip 方法。
  1. @Override
  2. protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  3.         // 获取所有候选 Advisor
  4.         List<Advisor> candidateAdvisors = findCandidateAdvisors();
  5.         // advisor 中 aspectName 如果和带创建的 beanName 一致,表明正在创建切面类实例,返回 true,表示切面类不需要代理
  6.         for (Advisor advisor : candidateAdvisors) {
  7.                 if (advisor instanceof AspectJPointcutAdvisor &&
  8.                                 ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
  9.                         return true;
  10.                 }
  11.         }
  12.         return super.shouldSkip(beanClass, beanName);
  13. }
复制代码
主要来看下 findCandidateAdvisors 这个方法。
  1. // AbstractAdvisorAutoProxyCreator
  2. protected List<Advisor> findCandidateAdvisors() {
  3.         Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
  4.         return this.advisorRetrievalHelper.findAdvisorBeans();
  5. }
复制代码
在 AspectJAwareAdvisorAutoProxyCreator 实例对象创建时,已经完成了 advisorRetrievalHelper 的创建赋值,是一个工具类 BeanFactoryAdvisorRetrievalHelper。
  1. // BeanFactoryAdvisorRetrievalHelper
  2. public List<Advisor> findAdvisorBeans() {
  3.         // Determine list of advisor bean names, if not cached already.
  4.         String[] advisorNames = this.cachedAdvisorBeanNames;
  5.         if (advisorNames == null) {
  6.                 // Do not initialize FactoryBeans here: We need to leave all regular beans
  7.                 // uninitialized to let the auto-proxy creator apply to them!
  8.                 // 获取注册的所有 Advisor 对应的名称集合
  9.                 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  10.                                 this.beanFactory, Advisor.class, true, false);
  11.                 this.cachedAdvisorBeanNames = advisorNames;
  12.         }
  13.         if (advisorNames.length == 0) {
  14.                 return new ArrayList<>();
  15.         }
  16.         List<Advisor> advisors = new ArrayList<>();
  17.         for (String name : advisorNames) {
  18.                 if (isEligibleBean(name)) {
  19.                         if (this.beanFactory.isCurrentlyInCreation(name)) {
  20.                                 if (logger.isTraceEnabled()) {
  21.                                         logger.trace("Skipping currently created advisor '" + name + "'");
  22.                                 }
  23.                         }
  24.                         else {
  25.                                 try {
  26.                                         // 对象未创建则在此时进行创建
  27.                                         advisors.add(this.beanFactory.getBean(name, Advisor.class));
  28.                                 }
  29.                                 catch (BeanCreationException ex) {
  30.                                         ...
  31.                                         // 抛出异常
  32.                                 }
  33.                         }
  34.                 }
  35.         }
  36.         return advisors;
  37. }
复制代码
bean 的创建过程,此处不再赘述。有几点需要留意:

  • 一个 pointcut 可以被多个 advisoraspect 下通知子标签引用,即可以在一个切入点应用多个顾问和通知,pointcut 对应的 beanClass 为 AspectJExpressionPointcut,创建 BeanDefinition 时设置 scope 为 prototype,以是每一个对 AspectJExpressionPointcut 的引用,都会创建一个新的对象。
  • aspect 标签下各个通知子标签对应的 Advisor 为 AspectJPointcutAdvisor,持有的 Advice 为通知子标签封装的 AspectJXXXAdvice。
  • AspectJPointcutAdvisor 构造方法注入时,需要 AbstractAspectJAdvice,而每一个 AspectJXXXAdvice 构造方法都需要三个参数,通报给父类 AbstractAspectJAdvice。
  1. public AbstractAspectJAdvice(
  2.                 Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
  3.         Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
  4.         this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
  5.         this.methodName = aspectJAdviceMethod.getName();
  6.         this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
  7.         this.aspectJAdviceMethod = aspectJAdviceMethod;
  8.         this.pointcut = pointcut;
  9.         this.aspectInstanceFactory = aspectInstanceFactory;
  10. }
复制代码
第一个参数,需要的是一个切面类中的通知方法,在 aspect 标签解析时,针对通知标签,封装一个 beanClass 为 MethodLocatingFactoryBean 的 BeanDefinition。当解析第一个参数时,会实行 MethodLocatingFactoryBean 的创建。
  1. // MethodLocatingFactoryBean
  2. @Override
  3. public void setBeanFactory(BeanFactory beanFactory) {
  4.         if (!StringUtils.hasText(this.targetBeanName)) {
  5.                 throw new IllegalArgumentException("Property 'targetBeanName' is required");
  6.         }
  7.         if (!StringUtils.hasText(this.methodName)) {
  8.                 throw new IllegalArgumentException("Property 'methodName' is required");
  9.         }
  10.         Class<?> beanClass = beanFactory.getType(this.targetBeanName);
  11.         if (beanClass == null) {
  12.                 throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
  13.         }
  14.         this.method = BeanUtils.resolveSignature(this.methodName, beanClass);
  15.         if (this.method == null) {
  16.                 throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
  17.                                 "] on bean [" + this.targetBeanName + "]");
  18.         }
  19. }
复制代码
会在 MethodLocatingFactoryBean 对象初始化时,完成目的通知方法的确定。
  1. // BeanUtils 根据方法名称从指定 clazz 中确定 method
  2. @Nullable
  3. public static Method resolveSignature(String signature, Class<?> clazz) {
  4.         Assert.hasText(signature, "'signature' must not be empty");
  5.         Assert.notNull(clazz, "Class must not be null");
  6.         int startParen = signature.indexOf('(');
  7.         int endParen = signature.indexOf(')');
  8.         if (startParen > -1 && endParen == -1) {
  9.                 throw new IllegalArgumentException("Invalid method signature '" + signature +
  10.                                 "': expected closing ')' for args list");
  11.         }
  12.         else if (startParen == -1 && endParen > -1) {
  13.                 throw new IllegalArgumentException("Invalid method signature '" + signature +
  14.                                 "': expected opening '(' for args list");
  15.         }
  16.         else if (startParen == -1) {
  17.                 // 不指定参数类型
  18.                 return findMethodWithMinimalParameters(clazz, signature);
  19.         }
  20.         else {
  21.                 // 方法名
  22.                 String methodName = signature.substring(0, startParen);
  23.                 // 逗号分割,获取参数类型数组
  24.                 String[] parameterTypeNames =
  25.                                 StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
  26.                 Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
  27.                 for (int i = 0; i < parameterTypeNames.length; i++) {
  28.                         String parameterTypeName = parameterTypeNames[i].trim();
  29.                         try {
  30.                                 // 加载类型,保证配置的每一个类型的正确性
  31.                                 parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
  32.                         }
  33.                         catch (Throwable ex) {
  34.                                 throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
  35.                                                 parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
  36.                         }
  37.                 }
  38.                 // 根据类型获取指定方法
  39.                 return findMethod(clazz, methodName, parameterTypes);
  40.         }
  41. }
  42. @Nullable
  43. public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
  44.                 throws IllegalArgumentException {
  45.         // 实际上 clazz.getMethods() 已经包含了当前类及所有父类中 public、protected 修饰的方法,但不包含 private 方法
  46.         Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
  47.         if (targetMethod == null) {
  48.                 // 当目标方法为 private 修饰时,通过以下方法查找
  49.                 targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
  50.         }
  51.         return targetMethod;
  52. }
  53. @Nullable
  54. public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
  55.                 throws IllegalArgumentException {
  56.         Method targetMethod = null;
  57.         int numMethodsFoundWithCurrentMinimumArgs = 0;
  58.         for (Method method : methods) {
  59.                 // 比较参数名称
  60.                 if (method.getName().equals(methodName)) {
  61.                         int numParams = method.getParameterCount();
  62.                         // 将参数长度最短的方法作为 targetMethod 返回
  63.                         if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
  64.                                 targetMethod = method;
  65.                                 numMethodsFoundWithCurrentMinimumArgs = 1;
  66.                         }
  67.                         else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
  68.                                 // 用常规方法覆盖桥接方法
  69.                                 if (targetMethod.isBridge()) {
  70.                                         // Prefer regular method over bridge...
  71.                                         targetMethod = method;
  72.                                 }
  73.                                 else {
  74.                                         // Additional candidate with same length
  75.                                         // 当存在方法重写或重载时,发现了两个名称和参数长度一样的方法,数量自增
  76.                                         numMethodsFoundWithCurrentMinimumArgs++;
  77.                                 }
  78.                         }
  79.                 }
  80.         }
  81.         // 存在方法重写时抛出异常,即不确定使用的是子类方法还是父类方法
  82.     // 重载时也会存在,方法名称一致,参数长度一致,但类型不一致,此处只校验长度,无法确定是哪一个方法
  83.         if (numMethodsFoundWithCurrentMinimumArgs > 1) {
  84.                 throw new IllegalArgumentException("Cannot resolve method '" + methodName +
  85.                                 "' to a unique method. Attempted to resolve to overloaded method with " +
  86.                                 "the least number of parameters but there were " +
  87.                                 numMethodsFoundWithCurrentMinimumArgs + " candidates.");
  88.         }
  89.         return targetMethod;
  90. }
  91. // 查找当前类,并递归父类,返回 public、protected、private 修饰方法
  92. @Nullable
  93. public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)
  94.                 throws IllegalArgumentException {
  95.         Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
  96.         if (targetMethod == null && clazz.getSuperclass() != null) {
  97.                 targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
  98.         }
  99.         return targetMethod;
  100. }
  101. @Nullable
  102. public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
  103.         try {
  104.                 return clazz.getMethod(methodName, paramTypes);
  105.         }
  106.         catch (NoSuchMethodException ex) {
  107.                 return findDeclaredMethod(clazz, methodName, paramTypes);
  108.         }
  109. }
复制代码
上面的代码解释了在切面类中确定目的通知方法的实现,主要逻辑如下:

  • 不指定方法参数类型时,按最短参数长度查找,指定参数类型时,按参数类型查找,也就是说,xml 中配置 methodName 时,可以是 methodName(argType1,argType2) 这种配置原型。
  • 不指定方法参数类型时,按最短参数长度查找,若存在方法重写和方法重载导致的多个方法名称和参数长度一致,会抛出异常
  • private 修饰的方法也可以被找到而作为目的通知方法
MethodLocatingFactoryBean 创建完成之后,由于是 FactoryBean 子类,会调用 this.beanFactory.getObjectFromFactoryBean 获取真正的对象。
  1. // MethodLocatingFactoryBean
  2. @Override
  3. @Nullable
  4. public Method getObject() throws Exception {
  5.         return this.method;
  6. }
复制代码
 可以看到,获取的 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 的实例化。
  1. public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
  2.         Assert.notNull(advice, "Advice must not be null");
  3.         this.advice = advice;
  4.         this.pointcut = advice.buildSafePointcut();
  5. }
复制代码
在构造方法中实行了 advice.buildSafePointcut(),这是在做什么呢?继续向下看。
  1. // AbstractAspectJAdvice
  2. public final Pointcut buildSafePointcut() {
  3.         // AspectJExpressionPointcut
  4.         Pointcut pc = getPointcut();
  5.         MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
  6.                         new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
  7.         // 组合
  8.         return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
  9. }
  10. // AspectJExpressionPointcut
  11. @Override
  12. public MethodMatcher getMethodMatcher() {
  13.         obtainPointcutExpression();
  14.         return this;
  15. }
  16. // AspectJExpressionPointcut
  17. private PointcutExpression obtainPointcutExpression() {
  18.         if (getExpression() == null) {
  19.                 throw new IllegalStateException("Must set property 'expression' before attempting to match");
  20.         }
  21.         if (this.pointcutExpression == null) {
  22.                 this.pointcutClassLoader = determinePointcutClassLoader();
  23.                 // 解析切入点表达式,创建 PointcutExpressionImpl 返回
  24.                 this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
  25.         }
  26.         return this.pointcutExpression;
  27. }
  28. public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
  29.         return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
  30.                         new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
  31. }
  32. public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
  33.         super(mm1, mm2);
  34. }
复制代码
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。
  1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  2.         if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
  3.                 return bean;
  4.         }
  5.         if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  6.                 return bean;
  7.         }
  8.         if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  9.                 this.advisedBeans.put(cacheKey, Boolean.FALSE);
  10.                 return bean;
  11.         }
  12.         // Create proxy if we have advice.
  13.         Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  14.         if (specificInterceptors != DO_NOT_PROXY) {
  15.                 this.advisedBeans.put(cacheKey, Boolean.TRUE);
  16.                 Object proxy = createProxy(
  17.                                 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  18.                 this.proxyTypes.put(cacheKey, proxy.getClass());
  19.                 return proxy;
  20.         }
  21.         this.advisedBeans.put(cacheKey, Boolean.FALSE);
  22.         return bean;
  23. }
复制代码
这是 spring 创建署理的模板。先来看对 Advisor 的过滤,找到当前目的类需要的 Advisor。
  1. // AbstractAdvisorAutoProxyCreator
  2. @Override
  3. @Nullable
  4. protected Object[] getAdvicesAndAdvisorsForBean(
  5.                 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  6.         List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  7.         if (advisors.isEmpty()) {
  8.                 return DO_NOT_PROXY;
  9.         }
  10.         return advisors.toArray();
  11. }
  12. // AbstractAdvisorAutoProxyCreator
  13. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  14.         // 获取所有 BeanFaactory 中定义的 Advisor,前面创建过,所以此处获取很快
  15.         List<Advisor> candidateAdvisors = findCandidateAdvisors();
  16.         // 筛选
  17.         List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  18.         // 扩展
  19.         extendAdvisors(eligibleAdvisors);
  20.         // 排序
  21.         if (!eligibleAdvisors.isEmpty()) {
  22.                 eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  23.         }
  24.         return eligibleAdvisors;
  25. }
  26. // AopUtils
  27. public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
  28.         if (candidateAdvisors.isEmpty()) {
  29.                 return candidateAdvisors;
  30.         }
  31.         List<Advisor> eligibleAdvisors = new ArrayList<>();
  32.         for (Advisor candidate : candidateAdvisors) {
  33.                 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
  34.                         eligibleAdvisors.add(candidate);
  35.                 }
  36.         }
  37.         boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  38.         for (Advisor candidate : candidateAdvisors) {
  39.                 if (candidate instanceof IntroductionAdvisor) {
  40.                         // already processed
  41.                         continue;
  42.                 }
  43.                 if (canApply(candidate, clazz, hasIntroductions)) {
  44.                         eligibleAdvisors.add(candidate);
  45.                 }
  46.         }
  47.         return eligibleAdvisors;
  48. }
  49. public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
  50.         if (advisor instanceof IntroductionAdvisor) {
  51.                 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
  52.         }
  53.         else if (advisor instanceof PointcutAdvisor) {
  54.                 // 对于 Advisor 为 DefaultBeanFactoryPointcutAdvisor,在进行 canApply 时执行 pc.getClassFilter 完成切入点表达式的解析
  55.                 PointcutAdvisor pca = (PointcutAdvisor) advisor;
  56.                 return canApply(pca.getPointcut(), targetClass, hasIntroductions);
  57.         }
  58.         else {
  59.                 // It doesn't have a pointcut so we assume it applies.
  60.                 return true;
  61.         }
  62. }
  63. public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
  64.         Assert.notNull(pc, "Pointcut must not be null");
  65.         if (!pc.getClassFilter().matches(targetClass)) {
  66.                 return false;
  67.         }
  68.         MethodMatcher methodMatcher = pc.getMethodMatcher();
  69.         if (methodMatcher == MethodMatcher.TRUE) {
  70.                 // No need to iterate the methods if we're matching any method anyway...
  71.                 return true;
  72.         }
  73.         IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  74.         if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
  75.                 introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  76.         }
  77.         Set<Class<?>> classes = new LinkedHashSet<>();
  78.         if (!Proxy.isProxyClass(targetClass)) {
  79.                 classes.add(ClassUtils.getUserClass(targetClass));
  80.         }
  81.         classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
  82.         for (Class<?> clazz : classes) {
  83.                 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
  84.                 for (Method method : methods) {
  85.                         if (introductionAwareMethodMatcher != null ?
  86.                                         introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
  87.                                         methodMatcher.matches(method, targetClass)) {
  88.                                 return true;
  89.                         }
  90.                 }
  91.         }
  92.         return false;
  93. }
复制代码
这些都是 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 对此方法进行了重写。
  1. @Override
  2. protected void extendAdvisors(List<Advisor> candidateAdvisors) {
  3.         AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
  4. }
  5. public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
  6.         // Don't add advisors to an empty list; may indicate that proxying is just not required
  7.         if (!advisors.isEmpty()) {
  8.                 boolean foundAspectJAdvice = false;
  9.                 for (Advisor advisor : advisors) {
  10.                         // Be careful not to get the Advice without a guard, as this might eagerly
  11.                         // instantiate a non-singleton AspectJ aspect...
  12.                         if (isAspectJAdvice(advisor)) {
  13.                                 foundAspectJAdvice = true;
  14.                                 break;
  15.                         }
  16.                 }
  17.                 if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
  18.                         advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
  19.                         return true;
  20.                 }
  21.         }
  22.         return false;
  23. }
  24. private static boolean isAspectJAdvice(Advisor advisor) {
  25.         return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
  26.                         advisor.getAdvice() instanceof AbstractAspectJAdvice ||
  27.                         (advisor instanceof PointcutAdvisor &&
  28.                                         ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
  29. }
复制代码
判定是否 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。
  1. // AbstractAutoProxyCreator
  2. protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
  3.                 @Nullable Object[] specificInterceptors, TargetSource targetSource) {
  4.         if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
  5.                 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  6.         }
  7.         ProxyFactory proxyFactory = new ProxyFactory();
  8.         proxyFactory.copyFrom(this);
  9.         if (proxyFactory.isProxyTargetClass()) {
  10.                 // Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
  11.                 if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
  12.                         // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
  13.                         for (Class<?> ifc : beanClass.getInterfaces()) {
  14.                                 proxyFactory.addInterface(ifc);
  15.                         }
  16.                 }
  17.         }
  18.         else {
  19.                 // No proxyTargetClass flag enforced, let's apply our default checks...
  20.                 if (shouldProxyTargetClass(beanClass, beanName)) {
  21.                         proxyFactory.setProxyTargetClass(true);
  22.                 }
  23.                 else {
  24.                         evaluateProxyInterfaces(beanClass, proxyFactory);
  25.                 }
  26.         }
  27.         Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  28.         proxyFactory.addAdvisors(advisors);
  29.         proxyFactory.setTargetSource(targetSource);
  30.         customizeProxyFactory(proxyFactory);
  31.         proxyFactory.setFrozen(this.freezeProxy);
  32.         // true
  33.         if (advisorsPreFiltered()) {
  34.                 proxyFactory.setPreFiltered(true);
  35.         }
  36.         // Use original ClassLoader if bean class not locally loaded in overriding class loader
  37.         ClassLoader classLoader = getProxyClassLoader();
  38.         if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
  39.                 classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
  40.         }
  41.         return proxyFactory.getProxy(classLoader);
  42. }
复制代码
创建署理的这一步,都是遵照 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 方法。
  1. // IntersectionIntroductionAwareMethodMatcher
  2. @Override
  3. public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
  4.         return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
  5.                         MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
  6. }
  7. // MethodMatches
  8. public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
  9.         Assert.notNull(mm, "MethodMatcher must not be null");
  10.         return (mm instanceof IntroductionAwareMethodMatcher ?
  11.                         ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
  12.                         mm.matches(method, targetClass));
  13. }
  14. // AdviceExcludingMethodMatcher
  15. @Override
  16. public boolean matches(Method method, Class<?> targetClass) {
  17.         return !this.adviceMethod.equals(method);
  18. }
复制代码
AdviceExcludingMethodMatcher 并不是 IntroductionAwareMethodMatcher 实例,调用 AdviceExcludingMethodMatcher#matches 方法判定目的方法是否是通知方法,不是返回 true。以是主要的判断还是基于 mm2,mm2 为 AspectJExpressionPointcut。
  1. // AspectJExpressionPointcut
  2. @Override
  3. public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
  4.         obtainPointcutExpression();
  5.         // org.aspectj.weaver.tools.ShadowMatch
  6.         ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
  7.         // Special handling for this, target, @this, @target, @annotation
  8.         // in Spring - we can optimize since we know we have exactly this class,
  9.         // and there will never be matching subclass at runtime.
  10.         if (shadowMatch.alwaysMatches()) {
  11.                 return true;
  12.         }
  13.         else if (shadowMatch.neverMatches()) {
  14.                 return false;
  15.         }
  16.         else {
  17.                 // the maybe case
  18.                 if (hasIntroductions) {
  19.                         return true;
  20.                 }
  21.                 // A match test returned maybe - if there are any subtype sensitive variables
  22.                 // involved in the test (this, target, at_this, at_target, at_annotation) then
  23.                 // we say this is not a match as in Spring there will never be a different
  24.                 // runtime subtype.
  25.                 RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
  26.                 return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
  27.         }
  28. }
复制代码
进入 AspectJExpressionPointcut#matches,委托给 AspectJ 进行切入点表达式和目的方法的匹配。
之后将筛选出的 Advisor,根据持有的通知类型的差异,适配成差异的 org.aopalliance.intercept.MethodInterceptor,封装成拦截器链。接着封装 MethodInvocation,调用 proceed 方法。
总结

介绍完了 AspectJ 下基于注解和 XML 的 AOP实现。现在我们来总结一下这两者的区别。
标签解析
实现方式标签解析器
注解AspectJAutoProxyBeanDefinitionParser
XMLConfigBeanDefinitionParser
署理生成器
实现方式署理生成器
注解AnnotationAwareAspectJAutoProxyCreator
XMLAspectJAwareAdvisorAutoProxyCreator
Advisor 的创建
实现方式署理生成器
注解AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
XMLAbstractAdvisorAutoProxyCreator#findCandidateAdvisors
注解方式下,AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors 方法,通过找到持有 @Aspect 注解的类,接着获取类中定义的通知方法,将其封装成 Advisor。
而 XML 模式下,由于在 XML 中已经定义了切面类、切入点、通知和顾问,以是会采用 spring 中定义的通用模板来获取 Advisor。
Advisor 的类型
实现方式Advisor 类型
注解InstantiationModelAwarePointcutAdvisorImpl
XMLadvisor 标签对应 DefaultBeanFactoryPointcutAdvisor
aspect 下通知子标签对应 AspectJPointcutAdvisor
除了这些显式的差异,还有一个隐式的差异点,就是 AspectJ 解析 expression 的时机
实现方式Advisor 类型AspectJ 解析 expression 的时机
注解InstantiationModelAwarePointcutAdvisorImplAbstractAdvisorAutoProxyCreator下findEligibleAdvisors 方法中对获取的 candidateAdvisors 进行筛选时完成
XMLDefaultBeanFactoryPointcutAdvisor
AspectJPointcutAdvisor有参构造方法实例化,实行 buildSafePointcut 方法时完成
下面我们来看下注解和 XML 这两种实现方式的共同点。
Advisor 的创建时机,都是在实行 AbstractAutoProxyCreator#postProcessBeforeInstantiation ,第一次调用 shouldSkip 方法时完成的,并将创建的 Advisor 实例对象加入到了 DefaultListableBeanFactory 的父类 DefaultSingletonBeanRegistry 中的 singletonObjects,之后获取 Advisor 时直接从 singletonObjects 获取。
业务 bean 署理对象的创建和方法调用,完全遵从 spring 中定义的 AOP 实现。至于方法匹配,则通过 AspectJExpressionPointcut 这个纽带,完全委托给了 AspectJ 这个框架去实现。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表