再开始之前对于 Spring XML 配置文件不熟悉的小伙伴可以看看我的 《死磕Spring之IoC篇 - 解析自定义标签(XML 文件)》 这篇文章。在 Spring 中对于非默认命名空间的标签需要通过指定的 NamespaceHandler 来处理,在 Spring 的 XML 配置文件中都是在 <beans /> 标签内定义数据,需要指定 作为命名空间,那么对于 就需要指定 NamespaceHandler 来处理。我们来看到 spring-aop 模块下的 META-INF/spring.handlers 配置文件:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandlerSpring AOP 相关的标签需要 AopNamespaceHandler 进行处理
AopNamespaceHandlerorg.springframework.aop.config.AopNamespaceHandler,继承 NamespaceHandlerSupport 抽象类,Spring AOP 命名空间下的标签处理器
public class AopNamespaceHandler extends NamespaceHandlerSupport { /** * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}' * and '{@code scoped-proxy}' tags. */ @Override public void init() { // In 2.0 XSD as well as in 2.1 XSD. // <aop:config /> 标签的解析器 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); // <aop:aspectj-autoproxy /> 标签的解析器 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); // <aop:scoped-proxy /> 标签的解析器 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } } public abstract class NamespaceHandlerSupport implements NamespaceHandler { private final Map<String, BeanDefinitionParser> parsers = new HashMap<>(); private final Map<String, BeanDefinitionDecorator> decorators = new HashMap<>(); protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { this.parsers.put(elementName, parser); } protected final void registerBeanDefinitionDecorator(String elementName, BeanDefinitionDecorator dec) { this.decorators.put(elementName, dec); } }在这个 NamespaceHandler 的 init() 初始化方法中,会往 parsers 中注册几个标签解析器或者装饰器:
<aop:config />:ConfigBeanDefinitionParser
<aop:aspectj-autoproxy />:AspectJAutoProxyBeanDefinitionParser
<aop:scoped-proxy />:ScopedProxyBeanDefinitionDecorator
继续看到 NamespaceHandlerSupport 这个方法:
@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // <1> 获得元素对应的 BeanDefinitionParser 对象 BeanDefinitionParser parser = findParserForElement(element, parserContext); // <2> 执行解析 return (parser != null ? parser.parse(element, parserContext) : null); } @Nullable private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 获得元素名 String localName = parserContext.getDelegate().getLocalName(element); // 获得 BeanDefinitionParser 对象 BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; } @Override @Nullable public BeanDefinitionHolder decorate( Node node, BeanDefinitionHolder definition, ParserContext parserContext) { // 根据标签名获取 BeanDefinitionDecorator 对象 BeanDefinitionDecorator decorator = findDecoratorForNode(node, parserContext); return (decorator != null ? decorator.decorate(node, definition, parserContext) : null); } @Nullable private BeanDefinitionDecorator findDecoratorForNode(Node node, ParserContext parserContext) { BeanDefinitionDecorator decorator = null; // 获得元素名 String localName = parserContext.getDelegate().getLocalName(node); if (node instanceof Element) { decorator = this.decorators.get(localName); } else if (node instanceof Attr) { decorator = this.attributeDecorators.get(localName); } else { parserContext.getReaderContext().fatal( "Cannot decorate based on Nodes of type [" + node.getClass().getName() + "]", node); } if (decorator == null) { parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionDecorator for " + (node instanceof Element ? "element" : "attribute") + " [" + localName + "]", node); } return decorator; }会根据标签名称找到对应的 BeanDefinitionParser 解析器进行解析,那么现在思路清晰了,上面不同的标签对应着不同的 BeanDefinitionParser 或者 BeanDefinitionDecorator,我们来看看是怎么处理的。
<aop:aspectj-autoproxy /> <beans> <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false" /> </beans>