Spring源码学习笔记(4)
Spring源码学习笔记(四)
前言--
最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的《Spring源码深度解析》这本书,会是个很好的入门。
开头写句话, 不会太尴尬 -- 前三篇在源码的角度梳理了 SpringMVC 的基本基本流程, 在接下来的内容回归 Spring 框架本身。 回顾 Spring 框架的功能的实现。 接下来进入正文。 o(* ̄︶ ̄*)o
Spring 容器
加载 Bean 的类:
通过 IntelliJ 的 show Diagram 功能获取到 DefaultListableBeanFactory 和 XmlBeanFactory 结构图。
------ DefaultListableBeanFactory 是 bean 加载的核心, 上图中的类都有其各自对应的功能和作用, 在接下来的探索中, 我们将会逐渐看到他们各自的身影。
读取 XML 配置文件的类:
无论是 Spring ,还是 Hibernate, Struts 框架, 其实现都是通过读取 XML 配置文件的信息来进行各种任务的执行。 在 Spring 框架中, 从 XmlBeanDefinitionReader 中瞄下读取资源文件的功能。首先, 还是看下 XmlBeanDefinitionReader 的结构图。
上面介绍了 Spring 的功能实现的两个重要的类, 接下来从代码的角度分析 Spring 从资源文件读取到加载 Bean 的逻辑。
资源文件的读取
在使用 Spring 容器加载 Bean 之前, 我们通常会通过指定 XML 配置文件告诉 Spring 容器在哪加载我们定义的 Bean, 即:
1 BeanFactory bf = new XmlBeanFactory(new ClassPathResource("***.xml"));
可以看到, Spirng 通过 ClassPathResource 类封装了资源配置文件。 查看 ClassPathResource 的结构
在其父接口 Resource 中, 定义了许多有关读取资源文件的方法:
1 public interface Resource extends InputStreamSource { 2 boolean exists(); 3 4 boolean isReadable(); 5 6 boolean isOpen(); 7 8 URL getURL() throws IOException; 9 10 URI getURI() throws IOException; 11 12 File getFile() throws IOException; 13 14 long contentLength() throws IOException; 15 16 long lastModified() throws IOException; 17 18 Resource createRelative(String var1) throws IOException; 19 20 String getFilename(); 21 22 String getDescription(); 23 }
需要我们关注的是在 Resource 接口的父接口 InputStreamSource 接口中的一个方法:
1 public interface InputStreamSource { 2 //第一步: 定义了流读取资源文件的方法 3 InputStream getInputStream() throws IOException; 4 }
了解了资源文件封装的类后, 再来看看 XmlBeanFactory 的初始化:
1 public class XmlBeanFactory extends DefaultListableBeanFactory { 2 private final XmlBeanDefinitionReader reader; 3 4 public XmlBeanFactory(Resource resource) throws BeansException { 5 this(resource, (BeanFactory)null); 6 } 7 // 第一步: 传入 Resource 8 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { 9 super(parentBeanFactory); //第二步: 调用父类的构造函数 10 this.reader = new XmlBeanDefinitionReader(this); 11 //第三步; 加载配置文件的方法 12 this.reader.loadBeanDefinitions(resource); 13 } 14 }
在 XmlBeanDefinition 的构造函数中,第二步调用父类构造函数的初始化方法:
1 public AbstractAutowireCapableBeanFactory() { 2 //第一步: 忽略实现指定接口的类 3 this.ignoreDependencyInterface(BeanNameAware.class); 4 this.ignoreDependencyInterface(BeanFactoryAware.class); 5 this.ignoreDependencyInterface(BeanClassLoaderAware.class); 6 }
在 XmlBeanDefinition 的构造函数中, 第三步加载配置文件的 loadBeanDefinitions() 真正实现了资源的加载:
1 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { 2 //第一步: XmlBeanDefinitionReader 中的 loadBeanDefinitions方法 , 封装了 EncodedResource 3 return this.loadBeanDefinitions(new EncodedResource(resource)); 4 }
在 loadBeanDefinitions() 方法中, 封装的 EncodedResource 处理了编码问题:
1 public Reader getReader() throws IOException { 2 return this.charset != null?new InputStreamReader(this.resource.getInputStream(), this.charset):(this.encoding != null?new InputStreamReader(this.resource.getInputStream(), this.encoding):new InputStreamReader(this.resource.getInputStream())); 3 }
然后进入 loadBeanDefinitions() 真正的实现逻辑:
1 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { 2 //第一步: 记录正在加载的资源 3 Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get(); 4 if(currentResources == null) { 5 currentResources = new HashSet(4); 6 this.resourcesCurrentlyBeingLoaded.set(currentResources); 7 } 8 9 if(!((Set)currentResources).add(encodedResource)) { 10 throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!"); 11 } else { 12 int var5; 13 try { 14 //第二步: 从 EncodedResource 获取 Resource 再 获取 InputStream 15 InputStream inputStream = encodedResource.getResource().getInputStream(); 16 17 try { 18 InputSource inputSource = new InputSource(inputStream); 19 if(encodedResource.getEncoding() != null) { 20 inputSource.setEncoding(encodedResource.getEncoding()); 21 } 22 //第三步: 进入核心逻辑 23 var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()); 24 } finally { 25 //第四步: 关闭流资源 26 inputStream.close(); 27 } 28 } catch (IOException var15) { 29 throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15); 30 } finally { 31 ((Set)currentResources).remove(encodedResource); 32 if(((Set)currentResources).isEmpty()) { 33 this.resourcesCurrentlyBeingLoaded.remove(); 34 } 35 36 } 37 38 return var5; 39 } 40 }
在 loadBeanDefinitions() 方法 的第三步中, doLoadBeanDefinitions() 实现了加载 BeanDefinition 的逻辑:
1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { 2 try { 3 //第一步: 加载文档, 验证文档的工作 4 Document doc = this.doLoadDocument(inputSource, resource); 5 //第二步: 注册加载的 BeanDefinition 6 return this.registerBeanDefinitions(doc, resource); 7 } 8 }
在 doLoadBeanDefinitions() 方法中, 第一步 doLoadDocument() 方法的实现:
1 protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { 2 //第一步: 对 XML 文件的验证, 获取文档并返回 3 return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware()); 4 }
在 doLoadDocument() 方法中, 第一步中 DocumentLoader 对象处理加载 Document 的逻辑:
1 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { 2 //第一步: 创建 DocumentBuilderFactory 3 DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware); 4 //第二步: 根据 DocumentBuilderFactory 创建 DocumentBuilder , 进而解析 Document 5 DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler); 6 return builder.parse(inputSource); 7 }
在 doLoadBeanDefinitions() 方法中, 第二步 registerBeanDefinitions() 实现注册 BeanDefinition 的逻辑:(在 XmlBeanDefinitionReader 中)
1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 2 //第一步: 创建 Reader 对象 3 BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader(); 4 documentReader.setEnvironment(this.getEnvironment()); 5 //第二步: 记录加载的个数 6 int countBefore = this.getRegistry().getBeanDefinitionCount(); 7 //第三步: 加载以及注册 BeanDefinition 8 documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource)); 9 return this.getRegistry().getBeanDefinitionCount() - countBefore; 10 }
在第一步 createBeanDefinitionDocumentReader() 方法中, 实例化 Reader 对象:
1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { 2 //第一步: 创建 Reader 对象 3 return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); 4 }
发现 this.documentReaderClass 属性:
1 private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
因此, 在 registerBeanDefinitions() 方法中, 第二步 registerBeanDefinitions() 方法的实现逻辑是在 DefaultBeanDefinitionDocumentReader 类中:
1 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { 2 this.readerContext = readerContext; 3 this.logger.debug("Loading bean definitions"); 4 Element root = doc.getDocumentElement(); 5 //第一步: 真正的处理逻辑 6 this.doRegisterBeanDefinitions(root); 7 }
1 protected void doRegisterBeanDefinitions(Element root) { 2 //第一步: 处理 profile 属性 (是 “dev” 或者 “production”) 3 String profileSpec = root.getAttribute("profile"); 4 if(StringUtils.hasText(profileSpec)) { 5 Assert.state(this.environment != null, "Environment must be set for evaluating profiles"); 6 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; "); 7 if(!this.environment.acceptsProfiles(specifiedProfiles)) { 8 return; 9 } 10 } 11 12 BeanDefinitionParserDelegate parent = this.delegate; 13 this.delegate = this.createDelegate(this.readerContext, root, parent); 14 //第二步: 解析前处理,子类实现 15 this.preProcessXml(root); 16 //第三步: 真正解析逻辑 17 this.parseBeanDefinitions(root, this.delegate); 18 //第四步: 解析后处理, 子类实现 19 this.postProcessXml(root); 20 this.delegate = parent; 21 }
在 doRegisterBeanDefinitions() 方法中, 第三步 parseBeanDefinition() 方法处理了 bean :
1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { 2 //第一步: 默认标签的处理 3 if(delegate.isDefaultNamespace(root)) { 4 NodeList nl = root.getChildNodes(); 5 6 for(int i = 0; i < nl.getLength(); ++i) { 7 Node node = nl.item(i); 8 if(node instanceof Element) { 9 Element ele = (Element)node; 10 if(delegate.isDefaultNamespace(ele)) { 11 //第二步: 处理默认标签 12 this.parseDefaultElement(ele, delegate); 13 } else { 14 //第三步: 处理自定义标签 15 delegate.parseCustomElement(ele); 16 } 17 } 18 } 19 } else { 20 //第四步: 处理自定义标签 21 delegate.parseCustomElement(root); 22 } 23 24 }
到此 Spring 容器读取资源文件, 并开始 解析默认的便签, 也就是 parseDefaultElement() 以及 parseCustomElement() 方法, 将在下一篇继续深入。
PERFECT EVERYTHING IN YOUR LIFE!!! KEEP ON GRINDING!! o(* ̄︶ ̄*)o