Spring中的上下文

一开看Spring源码的时候比较迷惑其实说白了,还是没有真正理解它里面的设计思路,今天突然之间开窍了,其实也不难理解!这里不会带你去深入源码,而是讲讲大概的思路。针对的可能就是一个面,不会太深入。

一想起上下文大家普遍都是知道语文中的上下文,这里也可以这么理解,这里其实是保证软件运行的前后环境,但也没那么大,只是传递一些必备的数据!有点像程序跳转语句,要保护现场!不过Spring中可不是这样,他是一种委托(Delegate),当程序分块时,不同的模块之间调用必然需要相应的数据,而这些数据就是我们所说的上下文,我们需要专门定义一些*Context.java文件来传递上下文,同时还有的地方定义了代理的模式。

由于Spring源码只读了两天,了解不多,日后了解了更多的知识再来更改补充!下面我就举两个例子,来说明这种设计思路!

XmlBeanDefinitionReader

大家可以看一下这个类的定义,在进行Bean解析注册的过程中我们用到了ReaderContext这个类。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 实例化一个BeanDefinitionDocumentReader使用DefaultBeanDefinitionDocumentReader实例化
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 统计当前BeanDefinition的个数
    // 在实例化BeanDefinitionReader的时候会将BeanDefinitionRegistry传入,默认使用继承自DefaultListableBeanFactory的子类
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 加载以及注册bean,并创建基于XML的readerContext,之后会传入用于资源方面的解析,这里面包含回调,错误处理等方面
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 记录本次加载的BeanDefinition的个数
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

里面有调用createReaderContext方法,而这个方法定义如下:

public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
            this.sourceExtractor, this, getNamespaceHandlerResolver());
}

看一下ReadContext中的属性:

public class ReaderContext {
    private final Resource resource;
    private final ProblemReporter problemReporter;
    private final ReaderEventListener eventListener;
    private final SourceExtractor sourceExtractor;
}

也许大家对这四个参数还是不明所以,这个需要深入去看代码,这里只是简单说明一下他们的意义:

  1. resource:xml资源文件最后生成的,这个不用说了,加载过程自己去看咯。
  2. problemReporter:是用于处理Bean定义处理过程中发生的错误和警告的工具,默认实现是打日志。
  3. eventListener:import、bean等过程中的解析完成的通知事件,这个可以深入源码查看,这里不多说!
  4. sourceExtractor:meta数据的预先处理

对于这四个元素XmlBeanDefinitionReader有相应的属性,我们来看一下:

/**
 *    用于定义错误处理,这里是默认值,可以改写,实现自己的错误处理流程!
 */
private ProblemReporter problemReporter = new FailFastProblemReporter();

/**
 * BeanDefinition过程的监听器,这里使用了默认的方式,我们也可以自己定义一个!
 */
private ReaderEventListener eventListener = new EmptyReaderEventListener();

/**
 * 可以在源meta数据被加入BeanDefinition前做一些处理。
 */
private SourceExtractor sourceExtractor = new NullSourceExtractor();

/**
 * XML的NameURI和Handler映射的处理,可用于设置自定义标签注册Handler
 */
private NamespaceHandlerResolver namespaceHandlerResolver;

他们都有相应的get和set方法,XMLReaderContext封装了他们,然后传入documentReader中进行处理。

哦,对了还有最重要的一点忘记说明了,这种方式使得我们可以自定义Spring的某些行为,在我们没有指定之前,他们使用的是默认的行为。我的注释上已经说明了这一点!打个比方我们可以放弃使用XMLBeanFactory,自己定义一个类XmlBeanDefinitionReader,然后这些默认的行为我们就可以改了,而XMLBeanFactory中的reader属性是private,也没有set和get方法,比较难以实现定制!

默认行为加上可定制的这种设计方式也很值得我们深入去学习!具体的实现请看源码!

BeanDefinitionParserDelegate

这是一个Bean定义解析的代理,这也是我们写代码可以借鉴学习的地方,学会里面的思路,按照这种方式来命名,程序会更好开发、阅读和维护。

里面有这种定义解析beans标签的方法:

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 获取自定义的命名空间
    String namespaceUri = getNamespaceURI(ele);
    // 从读取器上下文中,通过命名空间获取相应的标签处理Handler
    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));
}

看到了吗?这里定义了一个ParserContext,这个就是Handler需要处理和解析的上下文,里面的内容有读取上下文,当前的代理,包含当前标签的父标签。

另外还有Handler也是一种面向对象的一种抽象!

好吧这就是今天的一点总结吧!突然感觉,以前不敢碰的东西,没想到是如此简单!Fighting!

results matching ""

    No results matching ""