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;
}
也许大家对这四个参数还是不明所以,这个需要深入去看代码,这里只是简单说明一下他们的意义:
- resource:xml资源文件最后生成的,这个不用说了,加载过程自己去看咯。
- problemReporter:是用于处理Bean定义处理过程中发生的错误和警告的工具,默认实现是打日志。
- eventListener:import、bean等过程中的解析完成的通知事件,这个可以深入源码查看,这里不多说!
- 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!