前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring源码(八)

spring源码(八)

作者头像
写一点笔记
发布2020-09-21 15:40:36
4780
发布2020-09-21 15:40:36
举报

通过之前的学习我们大致上已经知道了SpringBoot启动的流程。到目前剩下的就是如何将BeanDefineMap中的类转化为真实的bean,然后注册到beanFactory的beanMap中了。那么onRefresh方法是否就是做这件事情的?

protected void onRefresh() {
    super.onRefresh();
    try {
        this.createWebServer();
    } catch (Throwable var2) {
        throw new ApplicationContextException("Unable to start web server", var2);
    }
}

我们看到在GenericWebApplicationContext中调用了

UiApplicationContextUtils.initThemeSource(this);方法。继续跟踪,我们进入initThemeSource这个方法。

public static ThemeSource initThemeSource(ApplicationContext context) {
  if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
//themeSource是否存在,不存在的时候创建,这里的getBean方法是关键
            ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
            // Make ThemeSource aware of parent ThemeSource.
            if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
                      HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
                      if (hts.getParentThemeSource() == null) {
                                // Only set parent context as parent ThemeSource if no parent ThemeSource
                                // registered already.
                                hts.setParentThemeSource((ThemeSource) context.getParent());
                      }
            }
            if (logger.isDebugEnabled()) {
                      logger.debug("Using ThemeSource [" + themeSource + "]");
            }
            return themeSource;
  }
  else {
//创建themeSource对象并返回。
            // Use default ThemeSource to be able to accept getTheme calls, either
            // delegating to parent context's default or to local ResourceBundleThemeSource.
            HierarchicalThemeSource themeSource = null;
            if (context.getParent() instanceof ThemeSource) {
                      themeSource = new DelegatingThemeSource();
                      themeSource.setParentThemeSource((ThemeSource) context.getParent());
            }
            else {
                      themeSource = new ResourceBundleThemeSource();
            }
            if (logger.isDebugEnabled()) {
                      logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
                                          "': using default [" + themeSource + "]");
            }
            return themeSource;
  }
}
//创建web服务
    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = this.getWebServerFactory();
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
        } else if (servletContext != null) {
            try {
                this.getSelfInitializer().onStartup(servletContext);
            } catch (ServletException var4) {
                throw new ApplicationContextException("Cannot initialize servlet context", var4);
            }
        }
        this.initPropertySources();
    }

这块是获取tomcat的,通过ServletWebServerFactory拿取servlet服务器

protected ServletWebServerFactory getWebServerFactory() {
    String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
    if (beanNames.length == 0) {
        throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
    } else if (beanNames.length > 1) {
        throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
    } else {
        return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }
}

代码运行到这里的时候,tomcat已经加载好了。

protected void initPropertySources() {
    ConfigurableEnvironment env = this.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, (ServletConfig)null);
    }

}

又进行了一次配置修改

public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
    WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}

创建完servlet服务器之后,就开始注册registerListener。这块就是上篇文档我们说到的ApplicationListenner接口。

执行完上述操作之后,我们看看finishBeanFactoryInitialization是做那些工作的。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();
}

通过debug发现,这个方法对bean进行实例化。

通过这个方法之后,singletonObjects被逐渐转化为bean实体。

在finishRefresh方法中

protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();
   // 初始化一个处理器initLifecycleProcessor();
   // 拿到处理器,并初始化lifecycle接口的类   getLifecycleProcessor().onRefresh();
   // 发布容器已经刷新的消息
   publishEvent(new ContextRefreshedEvent(this));
   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}

初始化有lifecycle接口的类

protected void initLifecycleProcessor() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
      this.lifecycleProcessor =
            beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
      }
   }
   else {
      DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
      defaultProcessor.setBeanFactory(beanFactory);
      this.lifecycleProcessor = defaultProcessor;
      beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
               "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
      }
   }
}
  //  这里开始调用lifecycle接口bean的方法
private void startBeans(boolean autoStartupOnly) {
//获取实现了lifecycle接口的bean
   Map, Lifecycle> lifecycleBeans = getLifecycleBeans();
   Map, LifecycleGroup> phases = new HashMap<>();
   lifecycleBeans.forEach((beanName, bean) -> {
      if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
         int phase = getPhase(bean);
         LifecycleGroup group = phases.get(phase);
         if (group == null) {
            group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
            phases.put(phase, group);
         }
         group.add(beanName, bean);
      }
   });
   if (!phases.isEmpty()) {
      Listkeys =new ArrayList<>(phases.keySet());
      Collections.sort(keys);
      for (Integer key : keys) {
         phases.get(key).start();
      }
   }
}

但是分析到这里就比较奇特了,这里只是启动启动了tomcat,那么tomcat是在哪里创建的?

我跟踪代码.

我们发现在OnRefresh方法中就创建了。我们看到OnRefresh方法有4个实现。

我们依次查看源代码,看看实现有什么差别。发现ServletWebServerApplicationContent和ReactiveWebServerApplicationContent都有Servlet容器服务的创建。

在这里突然想到,如果我们不做服务端也就是不想启动servlet容器,那么是不是就不用用剩余的两个content类?如果是这样的话,那么肯定在创建这里的content时候就决定了。我们知道当时创建content容器的时候得方法是createApplicationContent方法。

那么是不是我们设置了webApplicationType就可以了?通过研究发现确实是这样的。其实我一直觉得控制是否启动servlet容器的控制在于OnRefresh中,现在发现spring调用前就决定了一切。

SpringApplicationBuilder builder = new SpringApplicationBuilder(MergeeServic.class);
ApplicationContext applicationContext = builder.web(WebApplicationType.NONE).headless(false).run(args);

通过上述分析,springboot的过程已经解析的基本明确了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员备忘录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档