谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了java生态的spring不了解呢。

首先说一下spring做了啥,他将我们会频繁用到的javaBean交给spring的容器管理,在bean创建的不同阶段,可以在不同的容器中找到,说到底这些容器就是map缓存,有了spring我们就有了管家,可以过过当老爷的瘾,再也不用担心对象啥时候创建,初始化,销毁的问题了,用就完事了。

说了这么多废话,还是直接撸源码实在,首先看spring源码入口:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//为容器初始化做准备
// Prepare this context for refreshing.
prepareRefresh(); /* 1、创建BeanFactory对象
* 2、xml解析
* 传统标签解析:bean、import等
* 自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
* 自定义标签解析流程:
* a、根据当前解析标签的头信息找到对应的namespaceUri
* b、加载spring所以jar中的spring.handlers文件。并建立映射关系
* c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
* d、调用类的init方法,init方法是注册了各种自定义标签的解析类
* e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
*
* 3、把解析出来的xml标签封装成BeanDefinition对象
* */
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

这一个方法,包含了所有spring的操作,spring的代码果然是美如画,加上trycatch才十几行代码就改变了java的生态。

prepareRefresh();首先看看这个方法,有兴趣的可以自己看看,就是刷新上下文,设置启动日期之类的。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();我们主要看看这一行代码,进去看看

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//核心方法
refreshBeanFactory();
return getBeanFactory();
}

好像还看不到啥关键的,再看看refreshBeanFactory();

protected final void refreshBeanFactory() throws BeansException {

        //如果BeanFactory不为空,则清除BeanFactory和里面的实例
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId()); //设置是否可以循环依赖 allowCircularReferences
//是否允许使用相同名称重新注册不同的bean实现.
customizeBeanFactory(beanFactory); //解析xml,并把xml中的标签封装成BeanDefinition对象
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

1.首先做了判断,如果已经有了BeanFactory,就给他干掉,毕竟一山不容二虎嘛。

2.其次就是创建BeanFactory,其实里面就是new 了一个DefaultListableBeanFactory对象

3.设置循环依赖标识(默认就是支持的)

4.解析xml,封装成BeanDefinition对象(这个对象可是所有bean的胚胎,孕育着所有的bean)

好了,看到这四步应该都知道哪个重要了吧,我们进去看看xml解析是怎么做的:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//创建xml的解析器,这里是一个委托模式
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment()); //这里传一个this进去,因为ApplicationContext是实现了ResourceLoader接口的
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader); //主要看这个方法
loadBeanDefinitions(beanDefinitionReader);
}

1.首先用了一记委托模式(很多地方都用到了,就不一一介绍了,平时看源码的时候,稍微注意一点应该很容易发现),将xml解析的工作交给了XmlBeanDefinitionReader,一直往下调用loadBeanDefinitions直到:org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
//模板设计模式,调用到子类中的方法
count += loadBeanDefinitions(resource);
}
return count;
}

这边使用了模板设计模式,点进去任意选择一个类,可以看到都是实现了AbstractBeanDefinitionReader类的,选择xml解析实现:

            //获取Resource对象中的xml文件流对象
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//InputSource是jdk中的sax xml文件解析对象
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//主要看这个方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}

获取xml解析对象,继续向下:

            //把inputSource 封装成Document文件对象,这是jdk的API
Document doc = doLoadDocument(inputSource, resource); //主要看这个方法,根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;

再看如何将bean封装成BeanDefinition对象的:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//又来一记委托模式,BeanDefinitionDocumentReader委托这个类进行document的解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//主要看这个方法,createReaderContext(resource) XmlReaderContext上下文,封装了XmlBeanDefinitionReader对象
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

又一个委托模式,这是个老板啊,啥都让别人来做,再往下看:registerBeanDefinitions(doc, createReaderContext(resource));一直往下点:

protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> 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);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("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;
}

好像很复杂,好像啥也没干。可以看到preProcessXml和postProcessXml方法里面啥也没有,明显是个钩子方法,主要看parseBeanDefinitions(root, this.delegate);

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);
}
}

默认标签和自定义标签解析还是比较复杂的,看来一篇是讲不完了,下一篇再好好讲讲这一块。

总结:

写到现在,spring连标签解析都没开始,我们已经看到两个设计模式了,用心去看的话,工厂模式也是到处都在,单例模式贯穿了spring。在spring里面用到了很多设计模式和技巧,我们在看源码的同时,稍稍注意一下这些技巧的使用,并想一想,如果是我们要实现这些功能会怎么做,像spring这样的做法是否比你的想法更好呢,或者,如果你是大牛,你是否有更好的方法去实现spring的这一功能,如果有,去github上提交spring,那你在it界就小有名气了,嘿嘿!

最新文章

  1. C语言 &#183; 判定数字
  2. linux系统命令:yum和apt-get
  3. kylin1.5新特性 new aggregation group
  4. 数学语言和程序语言的对比:面向过程与面向集合&amp;命题
  5. 当多个客户请求一个servlet时,引擎为每个客户启动一个线程,那么servlet类的成员变量被所有的线程共享?
  6. phpcms v9为联动菜单字段添加验证提醒功能 解决标题不能为空
  7. IOS内存nil与release的区别
  8. hadoop源代码解读namenode高可靠:HA;web方式查看namenode下信息;dfs/data决定datanode存储位置
  9. Sping--IOC概念
  10. 《android开发艺术探索》读书笔记(五)--RemoteViews
  11. Java MD5加密与RSA加密
  12. C++初步 2
  13. Alibaba Cluster Data 开放下载:270GB 数据揭秘你不知道的阿里巴巴数据中心
  14. 【学习总结】GirlsInAI ML-diary day-12-for循环
  15. 【剑指offer】合并有序链表
  16. 利用WordPress REST API 开发微信小程序从入门到放弃
  17. Vue:v-on自定义事件
  18. Linux学习笔记:sed删除、插入数据
  19. iOS 应用中打开其他应用 (转)
  20. java 多线程之 interrupt()和线程终止方式

热门文章

  1. 用Python写个开心消消乐小游戏
  2. CCNP第二天之复习CCNA
  3. Backdrop Filter
  4. three.js WebGLRenderTarget
  5. 【代码周边】npm是What?
  6. ESP8266系列图片外观 Wi-Fi模块一共有01~14十多款模块
  7. 学习 Gin 总结(2020.12.30-31)
  8. 【NC基础操作】开发环境配置初体验
  9. [学习笔记]尝试go-micro开发微服务&lt;第一波&gt;
  10. navicat for mysql 破解版