Spring源码分析-AOP(一)预备知识

了解IOC容器初始化过程的同学一定知道,ico在初始化的时候会解析XML然后转换成Bean持有信息类BeanDefinition。阅读过IOC源码的同学也一定熟悉下面的代码,如果没有阅读过,不妨看一下我写的IOC源码系列。

在DefaultBeanDefinitionDocumentReader类的doRegisterBeanDefinitions方法(这个方法就是解析为BeanDefinition的入口)

protected void doRegisterBeanDefinitions(Element root) {
// Any nested elements will cause recursion in this method. In
// order to propagate and preserve default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String\[\] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI\_VALUE\_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles \[" + profileSpec +
                            "\] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }

    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}

spring在这里提供了xml配置文件解析的两个扩展接口:preProcessXml,postProcessXml. 用户可以根据自身需求扩展这两个接口。下面就关注一下上面代码里面加载bean的核心方法:parseBeanDefinition

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

从上面代码可以看出,xml配置文件里面的标签里面的闭合标签被解析成一个个Node。如果是默认的NameSpace标签 则分为import,alias,bean等标签进行解析并注册相应的bean,否则这调用parseCustomElement方法。

public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace \[" + namespaceUri + "\]", ele);
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

可以看到得到NamespaceHandler然后会调用parse方法。我们看一下是如何得到NamespaceHandler!点开resolve方法,NamespaceHandlerResolver只是个接口,其实现类是在DefaultNamespaceHandlerResolver。

public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException(“Class [“ + className + “] for namespace [“ + namespaceUri +
“] does not implement the [“ + NamespaceHandler.class.getName() + “] interface”);
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException(“NamespaceHandler class [“ + className + “] for namespace [“ +
namespaceUri + “] not found”, ex);
}
catch (LinkageError err) {
throw new FatalBeanException(“Invalid NamespaceHandler class [“ + className + “] for namespace [“ +
namespaceUri + “]: problem with handler class file or dependent class”, err);
}
}
}

spring为简化AOP在xml文件中的定义而创建了一个http://www.springframework.org/schema/aop命名空间,这里我简称为aop命名空间。spring在解析xml配置文件内容的过程中遇到非默认命名空间时,会查找系统中所有META-INF目录下的spring.handlers文件中与命名空间对应的处理器,我们可以在spring-aop-x.x.x-RELEASE.jar包的META-INF目录中的spring.handlers文件可以找到找到aop命名空间的处理器。

上面可以看到,先得到HandlerMapping,然后根据namespaceUri取到对应的handlerOrClassName。在反射出来得到NamespaceHandler。然后调用了init方法。譬如:这里我们就解析aop:config </aop:config>那么就是根据namespaceUri取出AopNamespaceHandler的全限定类名。然后反射出一个AopNamespaceHandler对象,再调用AopNamespaceHandler的init方法等

我们回到parseCustomElement继续向下看,此时我们得到了NamespaceHandler,然后调用parse方法。

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}

/\*\*
 \* Locates the {@link BeanDefinitionParser} from the register implementations using
 \* the local name of the supplied {@link Element}.
 */
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    String localName = parserContext.getDelegate().getLocalName(element);
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element \[" + localName + "\]", element);
    }
    return parser;
}

通过findParserForElement方法得到了一个BeanDefinitionParser,然后再调用该类的parse方法。

上面的都是aop知识的铺垫,下面的文章会用到这些。

坚持原创技术分享,您的支持将鼓励我继续创作!
  • 本文作者: XiuYu.Ge
  • 本文链接: 86.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!