Spring Framework核心容器启动流程

好的,各位听众,各位“码农”朋友们,欢迎来到今天的“Spring Framework核心容器启动流程深度游”特别节目!我是你们的老朋友,代码界的“段子手”——码不停蹄,今天就带大家一起扒一扒Spring这个“老司机”是怎么启动的,保证全程高能,让你听得懂、记得住、用得上!

开场白:Spring,你这个磨人的小妖精!

说起Spring,那真是Java界的一个“扛把子”,用的人多,坑也多(手动滑稽)。但不得不承认,它确实好用,依赖注入、AOP、事务管理,哪个不是开发者的心头好?但你有没有想过,Spring这个“魔术师”,到底是怎么把这些功能变出来的呢?今天我们就来揭秘一下它的核心容器启动流程,看看它到底在“后台”做了哪些不可告人的“秘密”。

第一站:BeanFactory,容器的“毛坯房”

首先,我们要认识一个非常重要的概念:BeanFactory。你可以把BeanFactory想象成一个“毛坯房”,它只是一个接口,定义了容器的基本功能,比如getBean(),用来获取Bean实例。BeanFactory的实现类有很多,比如XmlBeanFactory,它可以通过XML配置文件来创建Bean。

  • BeanFactory的职责:

    • 定义Bean的注册规范: 规定了Bean的命名、类型、依赖关系等。
    • 提供Bean的获取方式: 通过getBean()方法,我们可以从容器中获取Bean实例。
    • 管理Bean的生命周期: 负责Bean的创建、初始化、销毁等过程。
  • BeanFactory的特点:

    • 延迟加载: BeanFactory在启动时不会立即创建所有的Bean,而是在需要的时候才创建。
    • 轻量级: BeanFactory的实现比较简单,启动速度快,资源占用少。

第二站:ApplicationContext,容器的“精装修”

有了“毛坯房”,总得装修一下才能住人吧?ApplicationContext就是那个负责“精装修”的角色。ApplicationContext继承了BeanFactory,并在此基础上扩展了更多的功能,比如AOP、事件发布、国际化等。

  • ApplicationContext的职责:

    • 继承BeanFactory的所有功能: 拥有BeanFactory的所有特性。
    • 提供AOP支持: 可以通过配置,实现Bean的自动代理。
    • 支持事件发布: 可以发布自定义事件,实现组件之间的解耦。
    • 提供国际化支持: 可以根据不同的语言环境,加载不同的资源文件。
    • 提供资源访问支持: 可以访问文件系统、网络资源等。
  • ApplicationContext的特点:

    • 预加载: ApplicationContext在启动时会立即创建所有的单例Bean。
    • 功能强大: ApplicationContext提供了更多的功能,使用起来更方便。
    • 重量级: ApplicationContext的实现比较复杂,启动速度慢,资源占用多。

BeanFactory vs ApplicationContext:一个“抠脚大汉”,一个“精致Boy”

用一个形象的比喻来说,BeanFactory就像一个“抠脚大汉”,只关注最基本的功能,简单粗暴;而ApplicationContext就像一个“精致Boy”,不仅功能强大,还注重用户体验,体贴入微。

特性 BeanFactory ApplicationContext
加载方式 延迟加载 预加载
功能 简单,只提供基本功能 强大,提供更多高级功能
资源占用
启动速度
使用场景 对性能要求高的场景 对功能要求高的场景
比喻 抠脚大汉 精致Boy
灵魂拷问 “能用就行,要啥自行车?” “我要优雅,我要精致,我要全都要!”

第三站:启动流程详解,一步一个脚印

好了,认识了BeanFactory和ApplicationContext,接下来我们就深入了解一下ApplicationContext的启动流程,看看它是如何一步步把Bean创建出来的。

我们以最常用的ClassPathXmlApplicationContext为例,它会从classpath下加载XML配置文件。

1. 构造器阶段:

  • 创建实例: 首先,创建一个ClassPathXmlApplicationContext实例,并指定配置文件的路径。
  • 设置环境: 初始化Environment,用于访问系统属性、环境变量等。
  • 准备BeanFactory: 创建DefaultListableBeanFactory,这是Spring容器的核心实现类。
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
    this(configLocations, true, null);
}

public ClassPathXmlApplicationContext(
    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {

    super(parent); // 调用父类构造器
    setConfigLocations(configLocations); // 设置配置文件路径
    if (refresh) {
        refresh(); // 刷新容器
    }
}

2. refresh() 阶段:容器启动的核心!

refresh()方法是ApplicationContext启动的核心,它会完成Bean的加载、注册、初始化等一系列操作。

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新:设置启动日期、激活状态等。
        prepareRefresh();

        // 2. 获取BeanFactory:创建或获取BeanFactory实例。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 3. 准备BeanFactory:设置ClassLoader、Bean表达式解析器等。
        prepareBeanFactory(beanFactory);

        // 4. 后置处理BeanFactory:允许子类修改BeanFactory。
        postProcessBeanFactory(beanFactory);

        // 5. 调用BeanFactoryPostProcessor:执行BeanFactory的后置处理器。
        invokeBeanFactoryPostProcessors(beanFactory);

        // 6. 注册BeanPostProcessor:注册Bean的后置处理器。
        registerBeanPostProcessors(beanFactory);

        // 7. 初始化MessageSource:初始化国际化资源。
        initMessageSource();

        // 8. 初始化事件广播器:初始化事件广播器。
        initApplicationEventMulticaster();

        // 9. 注册监听器:注册监听器。
        onRefresh();

        // 10. 实例化单例Bean:创建所有非延迟加载的单例Bean。
        finishBeanFactoryInitialization(beanFactory);

        // 11. 发布事件:发布容器刷新完成事件。
        finishRefresh();
    }
}

我们来逐个击破,看看这些步骤都做了些什么:

  • 2. 获取BeanFactory: 如果容器中没有BeanFactory,则创建一个新的DefaultListableBeanFactory。
  • 3. 准备BeanFactory: 设置BeanFactory的一些属性,比如ClassLoader、Bean表达式解析器等。
  • 4. 后置处理BeanFactory: 这是一个扩展点,允许子类修改BeanFactory的配置。
  • 5. 调用BeanFactoryPostProcessor: BeanFactoryPostProcessor是一个接口,允许在BeanFactory创建之后,BeanDefinition加载之前,修改BeanDefinition的属性。常用的BeanFactoryPostProcessor有PropertyPlaceholderConfigurer,用于加载properties文件中的属性。这个步骤就像是“装修队”进场前,先把水电煤气管道铺设好。
    • 举个栗子?:
      • 假设你的XML配置文件中使用了${jdbc.url}这样的占位符,那么PropertyPlaceholderConfigurer就会负责把这些占位符替换成properties文件中对应的值。
  • 6. 注册BeanPostProcessor: BeanPostProcessor也是一个接口,允许在Bean创建前后进行一些处理。常用的BeanPostProcessor有AutowiredAnnotationBeanPostProcessor,用于处理@Autowired注解。这个步骤就像是“装修队”进场后,开始贴瓷砖、刷油漆,对Bean进行一些“美化”处理。
    • 举个栗子?:
      • AutowiredAnnotationBeanPostProcessor会扫描Bean中的@Autowired注解,并自动注入依赖的Bean。
  • 7. 初始化MessageSource: 初始化MessageSource,用于国际化资源的管理。
  • 8. 初始化事件广播器: 初始化事件广播器,用于发布和监听事件。
  • 9. 注册监听器: 注册监听器,用于监听容器中的事件。
  • 10. 实例化单例Bean: 这是最重要的一个步骤,它会创建所有非延迟加载的单例Bean。Spring会遍历所有的BeanDefinition,根据BeanDefinition的信息,创建Bean实例,并注入依赖的Bean。这个步骤就像是“装修队”开始组装家具、电器,把“毛坯房”变成一个可以居住的“家”。
    • Bean的创建过程:
      • 实例化: 通过反射或者构造器创建一个Bean实例。
      • 属性赋值: 根据BeanDefinition中的属性,为Bean实例赋值。
      • Aware接口回调: 如果Bean实现了Aware接口(比如BeanNameAware、BeanFactoryAware、ApplicationContextAware),则会回调相应的方法。
      • BeanPostProcessor前置处理: 调用BeanPostProcessor的postProcessBeforeInitialization()方法。
      • 初始化: 如果Bean实现了InitializingBean接口,则会调用afterPropertiesSet()方法;如果配置了init-method属性,则会调用指定的方法。
      • BeanPostProcessor后置处理: 调用BeanPostProcessor的postProcessAfterInitialization()方法。
      • 注册: 将Bean实例注册到容器中。
  • 11. 发布事件: 发布容器刷新完成事件,通知监听器容器已经启动完成。

表格总结:Spring容器启动流程

| 步骤 | 说明 步骤 | 说明

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注