死磕Spring之AOP篇 - Spring AOP注解驱动与XML配置 (5)

org.springframework.aop.config.ScopedProxyBeanDefinitionDecorator,<aop:scoped-proxy /> 标签对应的 BeanDefinitionDecorator 装饰器

class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator { private static final String PROXY_TARGET_CLASS = "proxy-target-class"; @Override public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { boolean proxyTargetClass = true; if (node instanceof Element) { Element ele = (Element) node; if (ele.hasAttribute(PROXY_TARGET_CLASS)) { proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)); } } // Register the original bean definition as it will be referenced by the scoped proxy // and is relevant for tooling (validation, navigation). // 创建一个 ScopedProxyFactoryBean 类型的 RootBeanDefinition 对象并注册 // ScopedProxyFactoryBean 用于装饰 `definition`,进行 AOP 代理 BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); parserContext.getReaderContext().fireComponentRegistered( new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); return holder; } } <aop:config /> <beans> <aop:aspectj-autoproxy/> <bean/> <aop:config> <aop:pointcut expression="execution(public String *(..))"/> <aop:advisor advice-ref="echoServiceMethodInterceptor" pointcut-ref="anyPublicStringMethod" /> <aop:aspect ref="aspectXmlConfig"> <aop:pointcut expression="execution(public * *(..))"/> <aop:around method="aroundAnyPublicMethod" pointcut-ref="anyPublicMethod"/> <aop:before method="beforeAnyPublicMethod" pointcut-ref="anyPublicMethod"/> <aop:before method="beforeAnyPublicMethod" pointcut="execution(public * *(..))"/> <aop:after method="finalizeAnyPublicMethod" pointcut-ref="anyPublicMethod"/> <aop:after-returning method="afterAnyPublicMethod" pointcut-ref="anyPublicMethod"/> <aop:after-throwing method="afterThrowingAnyPublicMethod" pointcut-ref="anyPublicMethod"/> </aop:aspect> </aop:config> </beans>

<aop:config> 标签内可以定义 AspectJ 切面的相关信息,例如 Pointcut、Advisor 和 Advice;同时也会注册一个 Spring AOP 自动代理对象(如果有必要的话),不过 是注册 AspectJAwareAdvisorAutoProxyCreator,只能解析处理 Spring IoC 中 Advisor 类型的 Bean,无法解析 @AspectJ 等相关注解,所以我们最好使用 <aop:aspectj-autoproxy/> 标签来驱动 Spring AOP 模块。

ConfigBeanDefinitionParser

org.springframework.aop.config.ConfigBeanDefinitionParser,<aop:config /> 标签对应的 BeanDefinitionParser 解析器,我们来看到它的 parse(..) 方法

@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); // <1> 解析 <aop:config /> 标签 // 注册 AspectJAwareAdvisorAutoProxyCreator 自动代理对象(如果需要的话),设置为优先级最高 // 过程和 @EnableAspectJAutoProxy、<aop:aspectj-autoproxy /> 差不多 configureAutoProxyCreator(parserContext, element); // <2> 获取 <aop:config /> 的子标签,遍历进行处理 List<Element> childElts = DomUtils.getChildElements(element); for (Element elt: childElts) { // 获取子标签的名称 String localName = parserContext.getDelegate().getLocalName(elt); if (POINTCUT.equals(localName)) { // <2.1> 处理 <aop:pointcut /> 子标签,解析出 AspectJExpressionPointcut 对象并注册 parsePointcut(elt, parserContext); } else if (ADVISOR.equals(localName)) { // <2.2> 处理 <aop:advisor /> 子标签,解析出 DefaultBeanFactoryPointcutAdvisor 对象并注册,了指定 Advice 和 Pointcut(如果有) parseAdvisor(elt, parserContext); } else if (ASPECT.equals(localName)) { // <2.3> 处理 <aop:aspectj /> 子标签,解析出所有的 AspectJPointcutAdvisor 对象并注册,里面包含了 Advice 对象和对应的 Pointcut 对象 // 同时存在 Pointcut 配置,也会解析出 AspectJExpressionPointcut 对象并注册 parseAspect(elt, parserContext); } } // <3> 将 `parserContext` 上下文中已注册的 BeanDefinition 合并到上面 `compositeDef` 中(暂时忽略) parserContext.popAndRegisterContainingComponent(); return null; }

该方法的处理过程如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygssw.html