spring ioc 的资源定位 载入和注册
来源:互联网 发布:python发送邮件带附件 编辑:程序博客网 时间:2024/06/13 04:37
Spring ioc的资源定位 载入和注册
以FileSystemXmlApplicationContext为例
package org.springframework.context.support;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.support.AbstractXmlApplicationContext;import org.springframework.core.io.FileSystemResource;import org.springframework.core.io.Resource;public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext() { }
public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent);}public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[]{configLocation}, true, (ApplicationContext)null);}public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, (ApplicationContext)null);}public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent);}public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, (ApplicationContext)null);}
--核心的构造方法基本其他的构造方法都是通过调用此方法进行的--
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if(refresh) { this.refresh(); }}protected Resource getResourceByPath(String path) { if(path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path);}
}
在核心的构造函数中发现调用了
- super(parent)
- this.setConfigLocations(configLocations);
- this.refresh()
理解为调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
然后,再调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。
通过追踪FileSystemXmlApplicationContext的继承体系。
1. ### 先看super(parent)
首先调用了父类AbstractXmlApplicationContext的构造
public AbstractXmlApplicationContext(ApplicationContext parent) { super(parent); }
继续
public AbstractRefreshableConfigApplicationContext(ApplicationContext parent) { super(parent); }
再继续
public AbstractApplicationContext(ApplicationContext parent) { this(); this.setParent(parent); }
this();的具体构造如下.
public AbstractApplicationContext() { this.logger = LogFactory.getLog(this.getClass()); this.id = ObjectUtils.identityToString(this); this.displayName = ObjectUtils.identityToString(this); this.beanFactoryPostProcessors = new ArrayList(); this.active = new AtomicBoolean(); this.closed = new AtomicBoolean(); this.startupShutdownMonitor = new Object(); this.applicationListeners = new LinkedHashSet(); this.resourcePatternResolver = this.getResourcePatternResolver(); } 从this.resourcePatternResolver =this.getResourcePatternResolver();跟进去会发现protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); }public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); //设置Spring的资源加载器 this.resourceLoader = resourceLoader; }
FileSystemXmlApplicationContext的继承体系如下:
- 由此继承体系可知道FileSystemXmlApplication的基类接口就是一个ResourceLoader而实现这个接口的类是DefautResourceLoader,所以默认的资源加载器会是DefautResourceLoader
- 由源码发现FileSystemXmlApplication通过调用父类AbstractXmlApplicationContext构造方法,该类又通过调用其父类AbstractRefreshableConfigApplicationContext的构造方法,AbstractRefreshableConfigApplicationContext类继续调用父类直到AbstractApplicationContext类后调用其默认构造方法,通过该类的getResourcePatternResolver()return new PathMatchingResourcePatternResolver返回一个ResourcePatternResolver实例有源码
public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; Resource[] getResources(String var1) throws IOException;} public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {.....}
由源码知道 ResourcePatternResolver、AbstractApplicationContext都继承了 ResourceLoader, PathMatchingResourcePatternResolver实现ResourcePatternResolver 所以AbstractApplicationContext、PathMatchingResourcePatternResolver都从而实现了spring中ResourceLoader的设置,这里也就仅仅是设置而已。
2. ## 再看this.setConfigLocations(configLocations)
/即多个资源文件路径之间用” ,; /t/n”分隔,解析成数组形式 public void setConfigLocation(String location) { this.setConfigLocations(StringUtils.tokenizeToStringArray(location, ",; \t\n")); } //解析Bean定义资源文件的路径,处理多个资源文件字符串数组public void setConfigLocations(String... locations) { if(locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for(int i = 0; i < locations.length; ++i) { // resolvePath为同一个类中将字符串解析为路径的方法 实际就是字符串 this.configLocations[i] = this.resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } } protected String resolvePath(String path) { return this.getEnvironment().resolveRequiredPlaceholders(path); } 至此,Spring IoC容器在初始化时将配置的Bean定义资源文件定位为Spring封装的Resource。
- ## 最后 this.refresh()
refresh()在基类AbstractApplicationContext中
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动 采用委派的方式即在类中只有一个abstract方法由子类实现。 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); <---这些方法先不管--> try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if(this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中
ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();
这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法 ,具体实现调用子类容器的refreshBeanFactory()方法 this.refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if(this.logger.isDebugEnabled()) { this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory); } return beanFactory; }
子类AbstractRefreshableApplicationContext实现refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException {//如果已经有容器,销毁容器中的bean,关闭容器 if(this.hasBeanFactory()) { this.destroyBeans(); this.closeBeanFactory(); } try { <!--创建ioc容器---> DefaultListableBeanFactory ex = this.createBeanFactory(); ex.setSerializationId(this.getId()); <!--对容器进行制定只要是true flase的设置--> this.customizeBeanFactory(ex); //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前 类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器 this.loadBeanDefinitions(ex); Object var2 = this.beanFactoryMonitor; synchronized(this.beanFactoryMonitor) { this.beanFactory = ex; }
看子类AbstractXmlApplicationContext中的loadBeanDefinitions方法
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {<!--创建bean资源读取器--> XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); <!--对reader进行一系列的设置 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); this.initBeanDefinitionReader(beanDefinitionReader); <!加载的地方 this.loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { /获取Bean定义资源的定位 //这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法 //该方法在ClassPathXmlApplicationContext中进行实现,对于我们 //举例分析源码的FileSystemXmlApplicationContext没有使用该方法 Resource[] configResources = this.getConfigResources(); if(configResources != null) { //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位 //的Bean定义资源 reader.loadBeanDefinitions(configResources); } 如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源 String[] configLocations = this.getConfigLocations(); if(configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
不是很到位的理解一下:
首先从FileSystemXmlApplicationContext这个类的refresh()启动,基类AbstractApplicationContext实现的在这个方法里同时调用了obtainFreshBeanFactory()而在 obtainFreshBeanFactory()里通过调用refreshBeanFactory()创建IoC容器、,并调用loadBeanDefinitions(beanFactory)装载bean,这两个方法都是通过委派实现的。 loadBeanDefinitions(beanFactory)中通过调用loadBeanDefinitions(beanDefinitionReader)实现bean加载,在loadBeanDefinitions(beanDefinitionReader)里Bean 读取器(reader)调用其父类AbstractBeanDefinitionReader读取定位的Bean定义资(这里用了两种方式一个是直接的url定位读取,另一种是在resource里面读取) 这里委派调用其子类XmlBeanDefinitionReader 的方法loadBeanDefinitions(resource),实现加载功能。在loadBeanDefinitions(resource)中调 用loadBeanDefinitions(EncodedResource encodedResource)载入XML形式Bean定义资源文件具体读取过程的方法doLoadBeanDefinitions(),在该 方法中调用documentLoader.loadDocument(..)把XML文件转换为DOc对象接着调用registerBeanDefinitions(Document doc, Resource resource) 按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构,该方法里面调用了registerBeanDefinitions(Document doc, XmlReaderContext readerContext)委派子类--根据 Spring DTD对Bean的定义规则解析Bean定义Document对象里面调用很多方法解析xml文件中所用标签例如:</bean>等。最后BeanDefinitionReaderUtils.registerBeanDefinition进入注册,当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正 完成注册功能的是DefaultListableBeanFactory.
- spring ioc 的资源定位 载入和注册
- Spring源码分析----IOC容器的实现(IoC容器的初始化过程(定位、载入解析、注册))
- Spring IOC (Bean的载入和注册)
- BeanDefinition的定位,载入和注册
- Spring IOC 源码阅读资源加载和注册
- Spring IOC 源码阅读资源加载和注册
- Spring IOC容器的初始化过程--资源定位
- Spring源码学习-3.IoC.资源的加载与注册
- Spring源码分析--Ioc容器定位解析资源文件并注册BeanDefinition
- 【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析
- Spring框架学习【IoC定位Bean资源】
- Spring源码阅读-- IOC容器资源定位
- Spring框架学习【IoC容器载入Bean资源文件】
- spring技术内幕3-IOC容器载入Bean定义资源
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【II】
- Spring源码学习IOC(3):IoC容器载入Bean定义资源文件
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的载入和解析1
- TypeScript XMLHttp客户端
- 滚动条美化jquery插件nicescroll的使用
- Spark-sql 连接hive中遇到的问题
- 解压打包练习题及扩展
- C++面试出现频率最高的30道题目
- spring ioc 的资源定位 载入和注册
- 简述Spring容器与SpringMVC的容器的联系与区别
- 10.1顺序表基本运算
- hdu 1233 kruskal + 并查集
- 浏览器兼容性问题解决方案 · 总结
- glew库安装和初始化
- gnvm--window下的nodejs版本管理工具
- 界面之下:还原真实的MV*模式
- bzoj 3156: 防御准备(斜率DP)