深入理解Spring IOC(二) 、从xml到BeanDefinition(下)

简介: 深入理解Spring IOC(二) 、从xml到BeanDefinition(下)

ClassPathApplicationContext 和 BeanDefinitionReader


我们上一篇开始有这么一段代码不知道大家还记得不:


public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath*:application-context.xml");
        ATest aTest = applicationContext.getBean(ATest.class);
        aTest.doSomeThing();
}


这段代码中ClassPathApplicationContext将我们的xml加载解析成了beanDefinition对象,并且转换成了最终的bean,我们经过前面的学习已经知道了XmlBeanDefinitionReader是怎样把xml解析成beanDefinition对象的,那么,在上面这段代码运行的时候,这个解析过程是发生在哪里呢?我们一起来看看ClassPathApplicationContext的构造方法:


代码块21
        public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    // 调用的是下边的这个方法
    this(new String[] {configLocation}, true, null);
  }
  public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
    super(parent);
    // 解析配置,此时参数是[classpath*:application-context.xml]
    setConfigLocations(configLocations);
    if (refresh) {
            // 调用下面的refresh方法
      refresh();
    }
  }



注意哈:这里我暂时只放refresh的前几行代码,因为其他的还和我们目前讲的没关系


代码块22
        @Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      // 1.加载前的准备工作
      prepareRefresh();
      // 2.获取一个全新的beanFactory实例
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 3.初始化beanFactory,给它设置各种
      prepareBeanFactory(beanFactory);


仅仅放出来了开始的那几行代码,是因为我们目前所说到的,也就和这个第二句有关系,我们直接来看2中的obtainFreshBeanFactory,它也是在AbstractApplicationContext中,


代码块23
        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
                // 重点
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
  }


重点是这第一行的这个方法,这个方法也是AbstractApplicationContext,但是它是个抽象方法,真正的实现是在AbstractRefreshableApplicationContext中,我们直接来看这里的refreshBeanFactory方法:


代码块24
        @Override
  protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
    }
    try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      // 加载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);
    }
  }


上面代码块中只有一句我给了注释,那个其实也是个抽象方法,真正的实现是在子类AbstractXmlApplicationContext中,我们到AbstractXmlApplicationContext中来:


代码块25
        @Override
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 1.我们前文所说过的XmlBeanDefinitionReader
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // 2.现在是在AbstractXmlApplicationContext,其父类既继承了DefaultResourceLoader的,也
    // 实现了ResourcePatternResolver
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    // 3.设置验证模型
    initBeanDefinitionReader(beanDefinitionReader);
    // 4.加载Resource
    loadBeanDefinitions(beanDefinitionReader);
  }

我们在这里直接就可以看到,ClassPathXmlApplicationContext就是用的XmlBeanDefinitionReader来加载解析Resource的,我们来看看上面代码块中3处的代码


代码块26
        protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
    reader.setValidating(this.validating);
  }


它调用的是XmlBeanDefinitionReader的内部方法,注意参数中this.validating的值是true,我们跟到这个方法中:


代码块27
        public void setValidating(boolean validating) {
    this.validationMode = (validating ? VALIDATION_AUTO : VALIDATION_NONE);
    this.namespaceAware = !validating;
  }


哈哈,这下应该是知道之前代码块7和8那里大量出现的validationMode的值是怎么来的了吧,其实就是在这里给赋值的,表示让程序去发现到底该使用怎样的解析方式。最后我们再来看看代码块25中4处的代码


代码块28
        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
    }
    // 实际走的是这里,因为上面的configResources此时是null
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
    }
  }


这个方法调用的就是我们前文所说过的XmlBeanDefinitionReader中的方法了,至此,xml怎样解析成BeanDefinition就已经说完,我们把我们到现在为止说到过的东西总结成下面的这张图:


1686810712641.png


我们可以看到,本篇讲的,其实就是最下面这部分的,下篇我们说从BeanDefinition是怎样变成Bean实例的。

目录
相关文章
|
1月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
8月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `<appender>` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `<logger>` 和 `<root>` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
2032 1
|
9月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
620 26
|
8月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
423 0
|
5月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
184 1
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
6月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
|
8月前
|
Java 容器 Spring
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
848 0