Spring源码学习第二节
2017-05-16 10:36
218 查看
IOC容器初始化过程
发起是上一节课,的refresh()来启动的。启动会进行,BeanDefinition的Resouce定位、载入和注册三个基本过程。(spring把三个过程分开了,在不同的模块完成,然后组合起来,这样就可以更加灵活的剪裁和扩展)。
FileSystemXmlApplicationContext的构造器允许传入string (Resource的文件路径)或数组(多个),已经其他IOC。refresh参数,是指定是否刷新将beanDefinition载入。
这个方法是在 BeanDefinitionReader类的loadBeanDefinition方法(使用的是模板模式,具体实现是由子类来完成的,也就是这里的getResourceByPath方法实现的)中调用的。
那么FileSystemXmlApplicationContext类是在父类AbstractRefreshableAppicationContext类中,定义BeanDefinitionReader从而完成bean读入。
AbstractRefreshableAppicationContext的 refreshBeanFactory方法。它被FileSystemXmlApplicationContext构造方法中refresh()调用。
createBeanFactory,getInternalParentBeanFactory是在AbstractAppicationContext实现获取双亲的IOC容器。
BeanDefinitionReader是顶层父类,重载了很多loadBeanDefinitions方法。实现是在AbstractBeanDefinitionReader类。但是最终调用的还是一个方法。
以DefaultListableBeanFactory为例,看IOC如何载入。
IOC初始化是调用refresh(),该方法是在父类,AbstractAppicationContext类中实现的。其中包含:BeanFactory更新、MessageSource和PostProcessor的注册。
之后看,AbstractRefreshableApplicationContext的refreshBeanFactory()方法(该方法在前面提到过)
上面讲的loadBeanDefinitions方法,是在AbstractXmlApplicationContext中实现,(存在2个方法,重载,另一个),初始化了读取器XmlBeanDefinitionReader。
该方法就是实现了reader(beanfactory),然后将beanDefinition设置到Factory
最终还是reader获取了resource然后进行一个配置的。所以最后的载入还是看Reader
AbstractBeanDefinitionReader ,已经为BeanDefinition做好了准备。我们调用的就是这个类的loadBeanDefinitions方法。
具体的读入方式,看子类。比如XmlBeanDefinitionReader。就继承了上面的Reader。并重写了方法。
继续调用的就是读入xml的流然后进行处理了。之后是由BeanDefinitionParserDelegate完成。
之后就是如何读取xml然后进行处理的流程。如何按照spring的Bean语义要求进行解析转化成内部数据结构,代码较多。这我放在下一节中
依赖注入一般发生在第一次通过getBean获取Bean,或者设置lazyinit属性。(是否想起了hibernate的懒加载?)
此时BeanDefinition信息以及在容器简历自己的数据结构,和表示。但还不能在容器直接使用,需要注册。
在DefaultListableBeanFactory中,定义了MAP
/* Map of bean definition objects, keyed by bean name /
private final Map
发起是上一节课,的refresh()来启动的。启动会进行,BeanDefinition的Resouce定位、载入和注册三个基本过程。(spring把三个过程分开了,在不同的模块完成,然后组合起来,这样就可以更加灵活的剪裁和扩展)。
1.Resource定位,它由ResourceLoader通过统一的Resource接口完成。
具体实现在上一节写过代码。获得配置文件的resource,通过reader将resource和factory结合。这样提现出applicationContext的好处了。有具体的FileSystemXmlApplicationContext这就是读取系统文件等。 由于已经继承了AbstractXmlApplicationContext类(最上层是Loader),所以具备了resourceLoader读入BeanDefinition的能力。
FileSystemXmlApplicationContext的构造器允许传入string (Resource的文件路径)或数组(多个),已经其他IOC。refresh参数,是指定是否刷新将beanDefinition载入。
protected Resource **getResourceByPath**(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }
这个方法是在 BeanDefinitionReader类的loadBeanDefinition方法(使用的是模板模式,具体实现是由子类来完成的,也就是这里的getResourceByPath方法实现的)中调用的。
那么FileSystemXmlApplicationContext类是在父类AbstractRefreshableAppicationContext类中,定义BeanDefinitionReader从而完成bean读入。
AbstractRefreshableAppicationContext的 refreshBeanFactory方法。它被FileSystemXmlApplicationContext构造方法中refresh()调用。
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { //如果已经建立了BeanFactory,则销毁并关闭beanFactory destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); //通过此方法构建了一个ioc容器来供applicationContext使用 beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); //载入BeanDefinition 启动 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
createBeanFactory,getInternalParentBeanFactory是在AbstractAppicationContext实现获取双亲的IOC容器。
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
BeanDefinitionReader是顶层父类,重载了很多loadBeanDefinitions方法。实现是在AbstractBeanDefinitionReader类。但是最终调用的还是一个方法。
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); //使用的是DefaultResourceLoader if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } //这里对Resource的路径解析。比如设定的各种ant格式的路径定义,得到需要的resource集合 if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // 同样是完成resource定位 Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } } getResource方法 看DefaultResourceLoader是如何实现的。 public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); if (location.startsWith("/")) { return getResourceByPath(location); } //如果路径带有classpath,进行下面的处理 else if (location.startsWith(CLASSPATH_URL_PREFIX)) { return new ClassPathResou 4000 rce(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); } else { try { // Try to parse the location as a URL... 处理URL定位 URL url = new URL(location); return new UrlResource(url); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. 如果都不是就交给子类实现 getResourceByPath方法 我们这里就是FileSystemXXX.实现 return getResourceByPath(location); }}}
2.BeanDefinition的载入,将用户定义好的bean表示成IOC的数据结构(BeanDefinition)。
通过HashMap来维护的。以DefaultListableBeanFactory为例,看IOC如何载入。
IOC初始化是调用refresh(),该方法是在父类,AbstractAppicationContext类中实现的。其中包含:BeanFactory更新、MessageSource和PostProcessor的注册。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 子类中启动refreshBeanFactory()的地方 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // 设置BeanFactory的后置处理 postProcessBeanFactory(beanFactory); // 调用BeanFactory的后处理器,这些后处理器是在Bean定义中向容器注册 invokeBeanFactoryPostProcessors(beanFactory); // 注册Bean的后处理器,在Bean创建过程中调用 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster(机制) for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.初始化其他的特殊bean onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. 初始化所有的单件 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. 发布容器事件,结束refresh过程 finishRefresh(); } catch (BeansException ex) { 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; } } }
之后看,AbstractRefreshableApplicationContext的refreshBeanFactory()方法(该方法在前面提到过)
protected final void refreshBeanFactory() throws BeansException { //是否已经存在IOC容器,如果存在销毁关闭。保证refresh之后是新的,更新bean if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //创建IOC容器 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //启动对BeanDefinition的载入 loadBeanDefinitions(beanFactory); //看参数,下面介绍存在一个重载方法,才是真正使用的loadBeanDefinition synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
上面讲的loadBeanDefinitions方法,是在AbstractXmlApplicationContext中实现,(存在2个方法,重载,另一个),初始化了读取器XmlBeanDefinitionReader。
该方法就是实现了reader(beanfactory),然后将beanDefinition设置到Factory
最终还是reader获取了resource然后进行一个配置的。所以最后的载入还是看Reader
AbstractBeanDefinitionReader ,已经为BeanDefinition做好了准备。我们调用的就是这个类的loadBeanDefinitions方法。
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { //这里是resource...,是多个文件。 Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { //这里的load方法,就是后面我们在子类重写的方法 counter += loadBeanDefinitions(resource); } return counter; }
具体的读入方式,看子类。比如XmlBeanDefinitionReader。就继承了上面的Reader。并重写了方法。
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
继续调用的就是读入xml的流然后进行处理了。之后是由BeanDefinitionParserDelegate完成。
之后就是如何读取xml然后进行处理的流程。如何按照spring的Bean语义要求进行解析转化成内部数据结构,代码较多。这我放在下一节中
3.向IOC容器注册BeanDefinition。调用BeanDefinitionRegistry接口来实现的。注入到一个Map中,进行管理。
不包含bean依赖注入的实现。它与载入是两个独立的过程。依赖注入一般发生在第一次通过getBean获取Bean,或者设置lazyinit属性。(是否想起了hibernate的懒加载?)
此时BeanDefinition信息以及在容器简历自己的数据结构,和表示。但还不能在容器直接使用,需要注册。
在DefaultListableBeanFactory中,定义了MAP
/* Map of bean definition objects, keyed by bean name /
private final Map
相关文章推荐
- Spring源码学习第二节
- spring学习笔记:Spring IOC容器,Spring源码
- spring学习笔记之AbstractController源码解读
- Spring IOC核心源码学习
- (精)Spring IOC核心源码学习III:bean标签和自定义标签实现原理
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(二)路径格式及解析方式(上) 推荐
- 学习Spring 附带源码jpetstore 一 安装配置篇
- spring源码学习笔记-初始化(二) PostProcessor
- spring源码学习笔记-初始化(五)-MessageSource/事件监听器
- spring源码学习笔记-初始化(四)-PostProcessor
- spring 源码学习 初始化(一)
- spring学习笔记之handler mapping源码解读
- Spring源码学习(一)------ IoC
- Spring源码学习(二)------ AOP
- spring源码学习笔记-初始化(六)-完成及异常处理
- spring学习笔记之DispatcherServlet源码解读
- Spring源码学习(二)------ AOP
- Spring源码学习(一)------ IoC
- 【Spring】IOC核心源码学习(二):容器初始化过程
- Spring源码学习-含有通配符路径解析(上) 推荐