Spring 容器的创建。obtainFreshBeanFactorr()中完成容器的创建。(BeanFactory关系类图,之前的执行流程可在本系列博客中看到)。接下来看容器创建的第二部,创建beanFactory


容器refresh总览:

     synchronized (this.startupShutdownMonitor) {// 设置环境,校验参数。prepareRefresh();// 创建BeanFactory(DefaultListableBeanFactor),加载bean定义信息。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();}}

obtainFreshBeanFactory 容器创建

容器初始化refresh方法中 obtainFreshBeanFactory用来创建容器实例

// AbstractApplicationContext中,重要的方法是refreshBeanFactory()方法
// getBeanFactory()不过是直接获取创建好的工厂protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;}

refreshBeanFactory()

refreshBeanFactory 方法在 AbstractApplicationContext的子类AbstractRefreshableApplicationContext中实现。

BeanDefinition: 是包含着类的定义信息,类的名字,作用域,是否懒加载等等描述bean的信息(也就是xml中配置的bean信息的封装)

 @Overrideprotected final void refreshBeanFactory() throws BeansException {// 如果工厂已经创建,销毁工厂if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 直接创建一个DefaultListableBeanFactory工厂DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());// 交给子类自定义配置customizeBeanFactory(beanFactory);// 加载beanDefinitionloadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

AbstractRefreshableApplicationContext 中对 customizeBeanFactory的实现

 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {// 是否允许bean定义覆盖(默认不允许)if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 是否允许循环依赖(默认不允许)if (this.allowCircularReferences != null) {beanFactory.setAllowCircularReferences(this.allowCircularReferences);}}

loadBeanDefinitions(beanFactory);

创建工厂中最重要的一步,加载bean的定义信息。

首先明确几个概念

  1. XXXResource:代表着资源文件
  2. XXXBeanDefinitionReader: 用于读取Resource,
  3. BeanDefinition: bean的描述信息,也就是xml中bean配置的描述的封装
 @Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// beanFactory本身是一个BeanDefinitionRegistry,用于注册bean信息// 创建 reader 读取 resourceXmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// 设置资源加载环境beanDefinitionReader.setEnvironment(this.getEnvironment());// 设置资源加载器,beanFactory也实现了ResourceLoader,用于将制定位置的资源,加载为ResourcebeanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// 给子类一个再次设置的机会initBeanDefinitionReader(beanDefinitionReader);// 加载bean定义信息loadBeanDefinitions(beanDefinitionReader);}protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}// 获取资源文件路径String[] configLocations = getConfigLocations();if (configLocations != null) {// 使用XmlBeanDefinitionReader加载资源reader.loadBeanDefinitions(configLocations);}}
XmlBeanDefinitionReader 加载 Resource
 @Overridepublic int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;for (String location : locations) {counter += loadBeanDefinitions(location);}return counter;}@Overridepublic int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return loadBeanDefinitions(location, null);}// 最终调用这个方法public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {// 获取资源加载器,也就是前面注册的beanFactory(它就是一个资源加载器这里用的是ClassPathXmlApplicationContext)ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {// 加载资源Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);// 加载bean定义信息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 {// Can only load single resources by absolute URL.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;}}

Resource[] resources ((ResourcePatternResolver)resourceLoader).getResources(location);

// this.resourcePatternResolver 在构造器中已经初始化完成。@Overridepublic Resource[] getResources(String locationPattern) throws IOException {return this.resourcePatternResolver.getResources(locationPattern);}

PathMarchingResourcePatternResolver获取资源

 @Overridepublic Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");// 如果以 classpath*:开头if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)// isPattern判断资源路径中是否包含* 或者 ?if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern);}else {// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));}}else {// Generally only look for a pattern after a prefix here,// and on Tomcat only after the "*/" separator for its "war:" protocol.int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :locationPattern.indexOf(':') + 1);if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern);}else {// a single resource with the given name// 提供的资源路径是 classpath:application.xml 最终调用这里。// 路径封装为一个Resourcereturn new Resource[] {getResourceLoader().getResource(locationPattern)};}}}

XmlBeanDefinitionReader 加载 Resource 已经完成,接下来就是使用Resource加载BeanDefinition。

XmlBeanDefinitionReader 加载BeanDefinition

AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable Set actualResources) 方法中,getConfigResources()已经获取资源完毕。

// 加载资源
Resource[] configResources = getConfigResources();
// 加载bean定义信息
int loadCount = loadBeanDefinitions(resources);
 @Overridepublic int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");int counter = 0;for (Resource resource : resources) {counter += loadBeanDefinitions(resource);}return counter;}@Overridepublic int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {// 统一编码封装return loadBeanDefinitions(new EncodedResource(resource));}public int loadBeanDefinitions(EncodedResource encodedResource) throws   BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (logger.isInfoEnabled()) {logger.info("Loading XML bean definitions from " + encodedResource.getResource());}
// resourceCurrentlyBeingLoaded是一个ThreadLocal,存放线程开始加载的资源Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet<>(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}try {// 获取resource流InputStream inputStream = encodedResource.getResource().getInputStream();try {// 包装为InputSourceInputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 加载bean定义信息return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}finally {inputStream.close();}}catch (IOException ex) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);}finally {currentResources.remove(encodedResource);if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}}
 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 使用dom解析文件Document doc = doLoadDocument(inputSource, resource);// 解析dom包装为beanDefinition,具体的解析过程比较复杂。// beanDefinitionRegistry就是上面的beanFactory,解析dom封装为beanDefinition后,保存到beanFactory中(就是调用beanDefinitionRegistry的registerBeanDefinition()方法)return registerBeanDefinitions(doc, resource);}....}

自此,beanFactory创建完成并且,beanDefinition也加载完成。

Spring容器创建流程(2)创建beanFactory,加载BeanDefinition相关推荐

  1. 关于Spring容器管理Bean的过程以及加载模式

    1.需要将bean的定义信息声明在Spring的配置文件中: 2.需要通过Spring抽象出的各种Resource来指定对应的配置文件: 3.需要显示声明一个Spring工厂,该工厂用来掌控我们在配置 ...

  2. Spring容器初始化和bean创建过程

    文章目录 Spring容器初始化过程(注解) 1.this() 初始化bean读取器和扫描器 2. register(annotatedClasses) 3 refresh()刷新上下文 前言:一直想 ...

  3. Spring容器启动流程+Bean的生命周期【附源码】

    如果对SpringIoc与Aop的源码感兴趣,可以访问参考:https://javadoop.com/,十分详细. 文章目录 Spring容器的启动全流程 Spring容器关闭流程 Bean 的生命周 ...

  4. 分析Spring容器启动流程 Spring初始化

    分析Spring容器启动流程 Spring初始化 每当启动Web容器时(例如Tomcat),会读取Web应用中的web.xml文件.以下这段代码就是启动Spring容器的关键代码. ContextLo ...

  5. 解决IDEA创建Maven工程时一直加载的问题

    解决创建Maven工程时一直加载的问题 先打开idea的->file->setting 然后直接搜索Maven. 然后搜索maven->Runner, 然后在Vm Options中输 ...

  6. Qt实用技巧:ubuntu发布程序打包流程(解决插件xcb加载失败)

    若该文为原创文章,未经允许不得转载 原博主博客地址:长沙红胖子Qt的博客_CSDN博客-Qt开发,图形图像处理,OpenCV图像处理领域博主 原博主博客导航:红胖子网络科技博文大全:开发技术集合(包含 ...

  7. 阿里面试真题:Spring容器启动流程

    有情怀,有干货,微信搜索[三太子敖丙]关注这个不一样的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文章. ...

  8. 如何使用jQuery创建“请稍候,正在加载...”动画?

    我想在我的网站上放置一个"请稍等,加载中"的旋转圆圈动画. 我应该如何使用jQuery完成此操作? #1楼 Jonathon的出色解决方案在IE8中中断(动画完全不显示). 要解决 ...

  9. asp.net 动态创建TextBox控件 如何加载状态信息

    接着上文Asp.net TextBox的TextChanged事件你真的清楚吗? 这里我们来说说状态数据时如何加载的. 虽然在Control中有调用状态转存的方法,但是这里有一个判断条件 if (_c ...

最新文章

  1. mybatis转义反斜杠_mybatis like 的坑
  2. Fedora Core 4配置本地yum源
  3. C++友元函数和友元类(二)
  4. 如何将html表单转换成url,JS表单传值和URL编码转换
  5. 论面向组合子程序设计方法 之 重构
  6. IM推送保障及网络优化详解(二):如何做长连接加推送组合方案
  7. Git 仓库设置记住密码
  8. hadoop学习4 调测错误备案
  9. BugkuCTF-PWN题pwn1-瑞士军刀
  10. 规格示例_最佳引导示例
  11. Java多张图片合成PDF
  12. NO.164 禅道的自定义功能:导航和主页的自定义
  13. java时间往后一天_往后余生,不能再陪你了
  14. Ubuntu下的QQ-For-Linux 安装
  15. Doc2Vec模型介绍及使用
  16. 看看淘宝的工程师如何评论12306
  17. 《读书是一辈子的事》中篇 了解未来
  18. 常用图片格式JPG\PNG\SVG该如何选择?
  19. win11电脑开移动热点,但是手机连不上
  20. 计算机普通话测试评分标准,计算机辅助普通话测试评分细则

热门文章

  1. 公司团建还真是一门智慧
  2. GIPC2018年度中国专利代理十强
  3. Windows 10修改环境变量方法
  4. CNN_TensorFlow图像分类代码
  5. virtual box中安装Mac OS后设置分辨率
  6. mysql查询耗时_一种数据库高耗时查询的自动取消方法与流程
  7. 苹果供应商:iPhone SE 3 5G和AirPods生产平稳
  8. 苹果推出36期免息分期?每月88元就能用上iPhone 13
  9. 罗永浩吐槽苹果功能更改 @库克:不要再胡来 做祸害用户体验的事
  10. iPhone 13系列电池容量最高4350mAh 较iPhone 12提升近20%