Spring refresh 方法分析之一

  • 三哥

内容来自【自学星球】

欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。

想要了解更多,欢迎访问👉:自学星球

--------------SSM系列源码文章及视频导航--------------

创作不易,望三连支持!

SSM源码解析视频

👉点我

Spring

  1. Spring 中注入 Bean 的各种骚操作做
  2. Spring 中Bean的生命周期及后置处理器使用
  3. Spring 中容器启动分析之refresh方法执行之前
  4. Spring refresh 方法分析之一
  5. Spring refresh 方法之二 invokeBeanFactoryPostProcessors 方法解析
  6. Spring refresh 方法分析之三
  7. Spring refresh 方法之四 finishBeanFactoryInitialization 分析
  8. Spring AOP源码分析一
  9. Spring AOP源码分析二
  10. Spring 事务源码分析

SpringMVC

  1. SpringMVC 启动流程源码分析
  2. SpringMVC 请求流程源码分析

MyBatis

  1. MyBatis 源码分析之 SqlSessionFactory 创建
  2. MyBatis 源码分析之 SqlSession 创建
  3. MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
  4. MyBatis 源码分析之 Select 语句执行(上)
  5. MyBatis 源码分析之 Select 语句执行(下)
  6. MyBatis 源码分析一二级缓存

---------------------【End】--------------------

一、refresh 方法之 prepareRefresh()

方法源码

org.springframework.context.support.AbstractApplicationContext#prepareRefresh

protected void prepareRefresh() {
    // 纪录启动时间
    this.startupDate = System.currentTimeMillis();
    // spring 标记为未关闭
    this.closed.set(false);
    // spring 当前激活状态
    this.active.set(true);

    // 打印一些日志
    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    // Initialize any placeholder property sources in the context environment
    // 空方法
    initPropertySources();

    // Validate that all properties marked as required are resolvable
    // see ConfigurablePropertyResolver#setRequiredProperties
    // 校验 xml 配置文件
    getEnvironment().validateRequiredProperties();

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    // 初始化 applicationListeners 监听容器
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

总结一下这个方法干了些啥:

  1. 记录启动时间,并且设置 Spring 为激活状态
  2. 校验 xml 配置文件
  3. 初始化 applicationListeners 监听容器

二、refresh 方法之 obtainFreshBeanFactory()

进入源码

org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 刷新 BeanFactory,并执行加载和解析配置文件的操作
    refreshBeanFactory();
    // 获取 beanFactory 并返回
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

这里显然重要的方法在 refreshBeanFactory 处,但结合我们的启动方式为 AnnotationConfigApplicationContext 类,所以我们会来到下面源码

org.springframework.context.support.GenericApplicationContext#refreshBeanFactory

protected final void refreshBeanFactory() throws IllegalStateException {
   if (!this.refreshed.compareAndSet(false, true)) {
      throw new IllegalStateException(
            "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
   }
   this.beanFactory.setSerializationId(getId());
}

嗯,很简单的几行代码,判断了是否为重复刷新及设置 Bean 工厂的序列化 id 就完事了。

那我们的配置文件解析呢!

这里不卖关子,因为我们是注解配置类方式启动,所以不需要执行解析配置文件并加载 Bean 定义等操作。但如果我们是 ClassPathXmlApplicationContext 方式启动 Spring 那么对应的 refreshBeanFactory 方法则如下:

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException {
    // 判断是否存在beanFactory
    if (hasBeanFactory()) {
        // 注销所有的单例 bean
        destroyBeans();
        // 重置beanFactory
        closeBeanFactory();
    }
    try {
        // 创建一个新的BeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 指定序列化id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
        beanFactory.setSerializationId(getId());
        // 定制BeanFactory
        customizeBeanFactory(beanFactory);
        // 加载 bean 定义(重点!!!!!!!!!!!!!)
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

总结一下这个方法干了些啥:

  1. 判断 beanFactory 是否存在,存在则销毁
  2. 创建一个新的 beanFactory 并设置相关属性
  3. 加载 Bean 定义(重点

而至于这个 loadBeanDefinitions 方法我不打算在这里进行分析,因为本次我分析的是注解方式启动,所以不会去解析 XML 进行 Bean 定义的加载。

后续如果有时间可以单独拿出来分析分析

番外资料:https://blog.csdn.net/weixin_38192427/article/details/116601007

三、refresh 方法之 prepareBeanFactory

方法源码

org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    // 设置上下文环境的启动类加载器
    beanFactory.setBeanClassLoader(getClassLoader());
    // 设置解析器,用于解析bean的定义中出现的spel表达式
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 添加一个属性编辑注册器,该接口有一个方法registerCustomEditors,用来设置自定义转换器
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    // 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于将spring的环境信息注入到实例化的bean中
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // bean在初始化时,如果bean含有某些属性(比如ResourceLoaderAware),则该属性不会被依赖注入
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    // 在普通工厂中,如果一个bean有BeanFactory.class属性,那么这个属性会被设置为beanFactory
    // 消息源会被注册(会被自动装配)为一个bean
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Register early post-processor for detecting inner beans as ApplicationListeners.
    // 早期注册的post-processor将会被添加作为检测内部的应用监听器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    // aop的代码织入,如果发现beanFactory中包含loadTimeWeaver的bean,则添加一个LoadTimeWeaverAwareProcessor
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        // 类型匹配设置一个暂时的类加载器
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    // 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }

    // 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    // 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

总结一下这个方法干了些啥:

  1. 向 BeanFactory 中设置一些属性(类加载器、解析spel表达式、自定义转换器等)
  2. 向 BeanFactory 中添加一些 Bean(XXXAware、监听器等)
  3. 忽略某些属性类型不被自动装配

四、refresh 方法之 postProcessBeanFactory

方法源码

org.springframework.context.support.AbstractApplicationContext#postProcessBeanFactory

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

显然这是要给空方法,后续 Spring 可能会对其扩展或者其子类进行实现。

比如我们自己继承 AnnotationConfigApplicationContext 类,并重写 postProcessBeanFactory 方法。

案例:

public class MyApplicationContext extends AnnotationConfigApplicationContext {

    // 此处完美继承父类的功能
    public  MyApplicationContext(Class<?>... componentClasses) {
        super(componentClasses);
    }

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 此处我们获取到了beanFactory对象
        // 通过调用beanFactory的API可以进行任何的操作。
        if (beanFactory instanceof DefaultListableBeanFactory){
            System.out.println(true);
        }
    }
}

测试

public class SpringDemo {
    public static void main(String[] args) {
        // 此处我随便注册了一个类
        MyApplicationContext myApplicationContext = new MyApplicationContext(Config.class);
        Phone phone = myApplicationContext.getBean(Phone.class);
    }
}

好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见


  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J3code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值