refreshContext(一)

简介: refreshContext

SpringBoot启动流程之(refreshContext)

  • 流程图:
  • 前面讲了Spring对于Context的基本处理
  • 这里补一下Context的基本类型的建立
  • 通过webApplicationType来加载不同的应用基本Context路径,最终通过反射来进行构建Context
  • 我们这里所使用的便是AnnotationConfigServletWebServerApplicationContext.class
  • AnnotationConfigServletWebServerApplicationContext的结构体
  • 来自其父类的Refresh:
  • refresh调用堆栈:
protected ConfigurableApplicationContext createApplicationContext(){
        Class<?> contextClass=this.applicationContextClass;
        if(contextClass==null){
        //根据当前应用类型加载基本Context环境
        try{
        switch(this.webApplicationType){
        case SERVLET:
        //我们是传统的Servlet应用,这里通过SPI加载了org.springframework.boot."
        //"web.servlet.context路劲下的AnnotationConfigServletWebServerApplicationContext类  
        contextClass=Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
        break;
//······删除了......

AbstractApplicationContext#refresh()

  • 这是一个模板方法,定义了一系列了的操作顺序集合

 

@Override
public void refresh()throws BeansException,IllegalStateException{
synchronized (this.startupShutdownMonitor){
        //准备上下文环境
        prepareRefresh();
        //建立beanFactory,加载了bean的定义,进行resources(xml,properties......)解析
        ConfigurableListableBeanFactory beanFactory=obtainFreshBeanFactory();
        //为beanFactory进行了各种填充
        prepareBeanFactory(beanFactory);
        try{
        //为beanFactory添加后置处理器,并且对Web应用程序(session......)
        //的各种生命域进行了注册,允许context子类对beanFactory进行后处理
        postProcessBeanFactory(beanFactory);
        //在context中注册、调用了beanFactory的后置处理器,并且对@Configration,@Bean......注解进行了处理,这里主要对bean的定义信息的配置
        invokeBeanFactoryPostProcessors(beanFactory);
        //注册实例化bean的拦截器
        registerBeanPostProcessors(beanFactory);
        //初始化ConfigurableListableBeanFactory的MessageSources
        initMessageSource();
        //初始化ApplicationEventMulticaster
        initApplicationEventMulticaster();
        // 初始化Tomcat容器,并且启动
        onRefresh();
        //listeners的注册,以及广播的发布
        registerListeners();
        // 初始化非惰性单例bean
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.
        finishRefresh();
        }
        catch(BeansException ex){
        // 清理已经创建的单例资源
        destroyBeans();
        // 重置激活状态
        cancelRefresh(ex);
        // Propagate exception to caller.
        throw ex;
        }
        finally{
        //重置Spring的常见反射元数据缓存
        resetCommonCaches();
        }
        }
        }

prepareRefresh();

• 初始化应用环境environment的Context以及Config
• 对listeners,event初始化
    protected void prepareRefresh(){
        // 激活容器.
        this.startupDate=System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if(logger.isDebugEnabled()){
        if(logger.isTraceEnabled()){
        logger.trace("Refreshing "+this);
        }
        else{
        logger.debug("Refreshing "+getDisplayName());
        }
        }
        //采用实际实例替换掉environment的Context以及Config,为当前无法操作,但是以后存在操作的预留的占位符
        initPropertySources();
        //验证Environment指定的属性不能为空
        getEnvironment().validateRequiredProperties();
        //为所有liteners初始化
        if(this.earlyApplicationListeners==null){
        this.earlyApplicationListeners=new LinkedHashSet<>(this.applicationListeners);
        }
        else{
        //重置所有Listeners
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        //初始化事件,保证广播一经创建,则发布所有事件
        this.earlyApplicationEvents=new LinkedHashSet<>();
        }

prepareRefresh->initPropertySources

  • initPropertySources细节
  • 调用堆栈image.png
  • 可以看出最终委托给了WebApplicationContextUtils#initServletPropertySources
  • 代码截图
  • 可以看出,该方法主要做的事就是初始化Environment的ServletContext以及ServletConfig

obtainFreshBeanFactory();

• obtainFreshBeanFactory代码体
• 建立了BeanFactory,并且对xml文件进行了读取,解释
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory(){
        //看后面
        refreshBeanFactory();
        return getBeanFactory();
        }

obtainFreshBeanFactory#refreshBeanFactory

protected final void refreshBeanFactory()throws BeansException{
        //当前是否存在bean工厂
        if(hasBeanFactory()){
        //如果存在则销毁这个工厂存在的所有单例bean
        destroyBeans();
        //然后初始化bean的id,置当前context的BeanFactory为空
        closeBeanFactory();
        }
        try{
        //默认创建DefaultListableBeanFactory工厂,并将此上下文父级的内部 bean工厂作为父bean工厂
        DefaultListableBeanFactory beanFactory=createBeanFactory();
        //为beanFactory设置序列化id
        beanFactory.setSerializationId(getId());
        //自定义beanFactory设置,是否允许覆盖同一key的bean;是否允许循环引用
        customizeBeanFactory(beanFactory);
        //加载定义bean的详细信息
        loadBeanDefinitions(beanFactory);
        this.beanFactory=beanFactory;
        }
        catch(IOException ex){
        throw new ApplicationContextException("I/O error parsing bean definition source for "+getDisplayName(),ex);
        }
        }

refreshBeanFactory->createBeanFactory

  • 销毁原来存在的beanFactory,为context创建一个级联beanFactory
protected DefaultListableBeanFactory createBeanFactory(){
        //默认此context创建一个DefaultListableBeanFactory.
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
        };
protected BeanFactory getInternalParentBeanFactory(){
        //如果实现了ConfigurableApplicationContext,则返回父上下文的内部bean工厂;否则,返回父上下文本身.
        return(getParent()instanceof ConfigurableApplicationContext?
        ((ConfigurableApplicationContext)getParent()).getBeanFactory():getParent());
        }

refreshBeanFactory->loadBeanDefinitions

  • loadBeanDefinitions抽象方法:image.png
  • 该接口定义了bean定义的规范方式,将bean定义加载到给定的bean工厂,通常通过委托给一个或多个BeanDefinitionReader实现
  • BeanDefinitionReader接口:
  • 这个接口实际上给出了对于bean定义读取的规范,主要包括以下几个方面
  • 怎么统一处理bean的定义,并且与bean工厂建立联系?
  • 加载bean资源的加载器从哪来?
  • bean定义的资源从哪里来?
  • bean的格式化转换怎么处理?
//bean定义阅读器的规范接口,但是不需要强制实现
public interface BeanDefinitionReader {
  /**
   * 返回bean工厂以注册bean定义.
   * 工厂通过BeanDefinitionRegistry接口暴露,
   * 封装了与bean定义处理相关的方法
   */
  BeanDefinitionRegistry getRegistry();
  /**
   * 获取资源加载器,以用于加载bean资源
   */
  @Nullable
  ResourceLoader getResourceLoader();
  /**
   * 获取bean的classLoader
   */
  @Nullable
  ClassLoader getBeanClassLoader();
  /**
   * 获取bean名字规范定义的加载器
   */
  BeanNameGenerator getBeanNameGenerator();
  /**
   * 从指定Resource加载bean的定义.
   */
  int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
  /**
   * 从多个Resource加载bean的定义.
   */
  int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
  /**
   * 从指定位置资源加载bean的定义
   */
  int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
  /**
   * 从多个指定位置资源加载bean的定义
   */
  int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

prepareBeanFactory(beanFactory)

  • 为obtainFreshBeanFactory产生的BeanFactory进一步完善,配置BeanFactory基于context的特征,其中主要定义了如下:
  • 指定了内部BeanFactory使用context的classloader
  • 使用上下文回调配置bean工厂(保留疑问,不知道干啥???)
  • 将environment注册为bean

postProcessBeanFactory(beanFactory)

  • 调用堆

ServletWebServerApplicationContext#postProcessBeanFactory

  • 为beanFactory添加后置处理器
  • 忽略某些自动装配的接口实现
  • 为Web应用注册所需要的所必须的bean

 

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
        //添加后置处理器,并且转化为bean
        beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
        //忽略ServletContextAware.class接口的自动装配
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        //BeanFactory注册web应用特有的局部作用域
        registerWebApplicationScopes();
        }

postProcessBeanFactory->registerWebApplicationScopes

private void registerWebApplicationScopes(){
        //构建request,session作用域,默认为null
        ExistingWebApplicationScopes existingScopes=new ExistingWebApplicationScopes(getBeanFactory());
        //初始化request= new RequestScope() ,session=new SessionScope(),并且刷新scope
        WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
        //为BeanFactory注册局部作用域(scope)
        existingScopes.restore();
        }
  • registerWebApplicationScopes
  • 代码段:
  • image.png
  • 可以看出其主要做了这几件事
  • 为应用注册了基础作用域
  • 为应用注册了request,session等......对应的解析器
目录
相关文章
|
5月前
|
Java 测试技术 Spring
Spring Boot 基于 JUnit 5 实现单元测试
Spring Boot 基于 JUnit 5 实现单元测试
165 0
|
编译器 数据安全/隐私保护 开发者
4.6 x64dbg 内存扫描与查壳实现
LyScript 插件中默认提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚不同函数之间的差异,本章内容将分别详细介绍每一种内存扫描函数是如何灵活运用,并实现一种内存查壳脚本,可快速定位目标程序加了什么壳以及寻找被加壳程序的入口点。软件查壳的实现原理可以分为静态分析和动态分析两种方式。静态分析是指在不运行被加壳程序的情况下,通过对程序的二进制代码进行解析,识别出程序是否被加壳,以及加壳的种类和方法。动态分析是指通过运行被加壳程序,并观察程序运行时的行为,识别程序是否被加壳,以及加壳的种类和方法。
|
5月前
|
存储 Java 编译器
第 4 章 对象与类(下)
第 4 章 对象与类
130 0
|
5月前
|
IDE Java 数据库连接
Lombok注解大全
这些是Lombok中的一些常见注解,它们可以显著减少Java代码中的冗余代码,提高代码的可读性和可维护性。不过,在使用Lombok之前,请确保你的开发环境已经配置好支持Lombok,通常需要安装相应的插件或进行设置以使IDE(如Eclipse、IntelliJ IDEA)能够正确解析Lombok注解。
91 2
|
JavaScript 前端开发 开发者
【三十天精通 Vue 3】 第十天 Vue 状态管理详解
【三十天精通 Vue 3】 第十天 Vue 状态管理详解
167 0
|
5月前
|
JSON 数据格式
使用 Gson 将 Map、List等转换为json string
使用 Gson 将 Map、List等转换为json string
114 0
|
5月前
|
JavaScript 前端开发
Vue如何监听键盘事件
Vue如何监听键盘事件
163 0
|
5月前
|
C语言
pinctrl dts学习笔记
pinctrl dts学习笔记
102 0
|
缓存 Java 数据库连接
Spring Boot 系统初始化器详解
Spring Boot 系统初始化器详解
196 0
|
Java 数据库 Maven
seata启动报错:at com.mysql.jdbc.connectionimpl.getservercharacterencoding(connectionimpl.java:3307)
seata启动报错:at com.mysql.jdbc.connectionimpl.getservercharacterencoding(connectionimpl.java:3307)