boot spring 解析csv_springboot源码架构解析ApplicationContextInitializer

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-31 21:38   21   0

说在前面

前期回顾

sharding-jdbc源码解析 更新完毕

spring源码解析 更新完毕

spring-mvc源码解析 更新完毕

spring-tx源码解析 更新完毕

spring-boot源码解析 更新完毕

rocketmq源码解析 更新完毕

dubbbo源码解析 更新完毕

netty源码解析 更新完毕

spring源码架构更新完毕

spring-mvc源码架构更新完毕

springboot源码架构更新中

github https://github.com/tianheframe

sharding-jdbc源码解析 更新完毕

rocketmq源码解析 更新完毕

seata 源码解析 更新完毕

dubbo 源码解析 更新完毕

netty 源码解析 更新完毕

源码解析

a99959eccfa20c5a9976bc5d36bd6704.png

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer 配置错误的ApplicationContextInitializer实现

@Override  public void initialize(ConfigurableApplicationContext context) {    context.addBeanFactoryPostProcessor(        new ConfigurationWarningsPostProcessor(getChecks()));  }

添加ConfigurationWarningsPostProcessor,获得检查项org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#getChecks

protected Check[] getChecks() {    return new Check[] { new ComponentScanPackageCheck() };  }

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck

static {      Set<String> packages = new HashSet<String>();//      默认会扫描org.springframework下所有的包      packages.add("org.springframework");      packages.add("org");      PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);    }

检查指定的包

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor实现org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor接口。

@Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)        throws BeansException {    }

获得BeanFactory参数,可以对BeanFactory中的BeanDefinition进行处理

  @Override    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)        throws BeansException {      for (Check check : this.checks) {        String message = check.getWarning(registry);        if (StringUtils.hasLength(message)) {          warn(message);        }      }    }

确认检查信息,发出警告

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck

@Override    public String getWarning(BeanDefinitionRegistry registry) {      Set<String> scannedPackages = getComponentScanningPackages(registry);      List<String> problematicPackages = getProblematicPackages(scannedPackages);      if (problematicPackages.isEmpty()) {        return null;      }      return "Your ApplicationContext is unlikely to "          + "start due to a @ComponentScan of "          + StringUtils.collectionToDelimitedString(problematicPackages, ", ")          + ".";    }

获得@ComponentScan指定的包,匹配spring的包,如果包含报错

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck#getComponentScanningPackages 获得要扫描的包

  protected Set<String> getComponentScanningPackages(        BeanDefinitionRegistry registry) {      Set<String> packages = new LinkedHashSet<String>();//      获得BeanFactory中所有的BeanDefinition名称      String[] names = registry.getBeanDefinitionNames();      for (String name : names) {//        获取指定名称的BeanDefinition        BeanDefinition definition = registry.getBeanDefinition(name);        if (definition instanceof AnnotatedBeanDefinition) {          AnnotatedBeanDefinition annotatedDefinition = (AnnotatedBeanDefinition) definition;//          添加AnnotatedBeanDefinition指定的包名          addComponentScanningPackages(packages,              annotatedDefinition.getMetadata());        }      }      return packages;    }

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck#addComponentScanningPackages 添加@ComponentScan指定的包

private void addComponentScanningPackages(Set packages,        AnnotationMetadata metadata) {//      获取@ComponentScan属性      AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata          .getAnnotationAttributes(ComponentScan.class.getName(), true));      if (attributes != null) {        addPackages(packages, attributes.getStringArray("value"));        addPackages(packages, attributes.getStringArray("basePackages"));//        类所在的包        addClasses(packages, attributes.getStringArray("basePackageClasses"));//        如果都没有指定添加元数据中指定的包名        if (packages.isEmpty()) {          packages.add(ClassUtils.getPackageName(metadata.getClassName()));        }      }    }

org.springframework.boot.web.support.ServletContextApplicationContextInitializer 设置servletContext的ApplicationContextInitializer

  private final ServletContext servletContext;

servletContext

@Override  public void initialize(ConfigurableWebApplicationContext applicationContext) {    applicationContext.setServletContext(this.servletContext);    if (this.addApplicationContextAttribute) {      this.servletContext.setAttribute(          WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,          applicationContext);    }  }

设置ApplicationContext的servletContext

org.springframework.boot.builder.ParentContextApplicationContextInitializer 用于设置父上下文的ApplicationContextInitializer。还发布ParentContextApplicationContextInitializer。当上下文被刷新时,ParentContextAvailableEvent向其他侦听器发出信号,表明上下文可用并具有父上下文。

  private final ApplicationContext parent;

ApplicationContext

  @Override    public void onApplicationEvent(ContextRefreshedEvent event) {      ApplicationContext context = event.getApplicationContext();      if (context instanceof ConfigurableApplicationContext          && context == event.getSource()) {        context.publishEvent(new ParentContextAvailableEvent(            (ConfigurableApplicationContext) context));      }    }  }

发布ApplicationContext事件

org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer 为嵌入servletcontainer服务器实际监听的端口设置环境属性。local.server财产”。port”可以直接使用@Value注入到测试中,也可以通过环境获得。如果EmbeddedWebApplicationContext有一个名称空间集,它将用于构造属性名。例如,“management”执行器上下文将具有属性名称“local.management.port”。属性将自动传播到任何父上下文。

  @Override  public void initialize(ConfigurableApplicationContext applicationContext) {    applicationContext.addApplicationListener(        new ApplicationListener() {          @Override          public void onApplicationEvent(              EmbeddedServletContainerInitializedEvent event) {            ServerPortInfoApplicationContextInitializer.this                .onApplicationEvent(event);          }        });  }

添加serverPort相关的ApplicationContextInitializer

org.springframework.boot.context.config.DelegatingApplicationContextInitializer 将委托给在context.initializer下指定的其他初始化器的ApplicationContextInitializer。类环境属性。

@Override  public void initialize(ConfigurableApplicationContext context) {    ConfigurableEnvironment environment = context.getEnvironment();    List> initializerClasses = getInitializerClasses(environment);    if (!initializerClasses.isEmpty()) {      applyInitializerClasses(context, initializerClasses);    }  }

加载配置的初始化类,org.springframework.boot.context.config.DelegatingApplicationContextInitializer#getInitializerClasses 从配置文件中加载context.initializer.classes属性指定的初始化类

private List> getInitializerClasses(ConfigurableEnvironment env) {//    从配置文件中加载初始化类context.initializer.classes    String classNames = env.getProperty(PROPERTY_NAME);    List> classes = new ArrayList>();    if (StringUtils.hasLength(classNames)) {      for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {        classes.add(getInitializerClass(className));      }    }    return classes;  }
private void applyInitializerClasses(ConfigurableApplicationContext context,      List> initializerClasses) {    Class> contextClass = context.getClass();    List> initializers = new ArrayList>();    for (Class> initializerClass : initializerClasses) {//      初始化初始化器      initializers.add(instantiateInitializer(contextClass, initializerClass));    }    applyInitializers(context, initializers);  }

初始化初始化的类并执行,org.springframework.boot.context.config.DelegatingApplicationContextInitializer#instantiateInitializer初始化初始化类

  private ApplicationContextInitializer> instantiateInitializer(Class> contextClass,      Class> initializerClass) {    Class> requireContextClass = GenericTypeResolver.resolveTypeArgument(        initializerClass, ApplicationContextInitializer.class);    Assert.isAssignable(requireContextClass, contextClass,        String.format(            "Could not add context initializer [%s]"                + " as its generic parameter [%s] is not assignable "                + "from the type of application context used by this "                + "context loader [%s]: ",            initializerClass.getName(), requireContextClass.getName(),            contextClass.getName()));    return (ApplicationContextInitializer>) BeanUtils        .instantiateClass(initializerClass);  }

org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializers执行org.springframework.context.ApplicationContextInitializer#initialize方法

private void applyInitializers(ConfigurableApplicationContext context,      List> initializers) {    Collections.sort(initializers, new AnnotationAwareOrderComparator());    for (ApplicationContextInitializer initializer : initializers) {//      执行初始化器的初始化方法      initializer.initialize(context);    }  }

org.springframework.boot.context.ContextIdApplicationContextInitializer 设置Spring ApplicationContext ID的ApplicationContextInitializer。

org.springframework.boot.web.support.SpringBootServletInitializer 实现了org.springframework.web.WebApplicationInitializer接口,一个固执己见的WebApplicationInitializer,用于从传统的WAR部署运行spring应用程序。将Servlet、Filter和ServletContextInitializer bean从应用程序上下文绑定到Servlet容器。要配置应用程序,要么重写configure(SpringApplicationBuilder)方法(调用SpringApplicationBuilder.sources(Object…)),要么将初始化器本身设置为@Configuration。如果您将SpringBootServletInitializer与其他webapplicationinitialalizer结合使用,您可能还想添加一个@Ordered注释来配置特定的启动顺序。注意,只有在构建和部署war文件时才需要WebApplicationInitializer。如果您喜欢运行嵌入式容器,那么您根本不需要这个。

@Override  public void onStartup(ServletContext servletContext) throws ServletException {    // Logger initialization is deferred in case a ordered    // LogServletContextInitializer is being used    this.logger = LogFactory.getLog(getClass());//    创建web应用上下文    WebApplicationContext rootAppContext = createRootApplicationContext(        servletContext);    if (rootAppContext != null) {      servletContext.addListener(new ContextLoaderListener(rootAppContext) {        @Override        public void contextInitialized(ServletContextEvent event) {          // no-op because the application context is already initialized        }      });    }    else {      this.logger.debug("No ContextLoaderListener registered, as "          + "createRootApplicationContext() did not "          + "return an application context");    }  }

创建WebApplicationContext,启动SpringApplication程序,org.springframework.boot.web.support.SpringBootServletInitializer#createRootApplicationContext 创建WebApplicationContext

protected WebApplicationContext createRootApplicationContext(      ServletContext servletContext) {//    创建SpringApplicationBuilder    SpringApplicationBuilder builder = createSpringApplicationBuilder();//    设置application启动的main方法所在类    builder.main(getClass());//    是否存在web应用上下文    ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);    if (parent != null) {      this.logger.info("Root context already created (using as parent).");      servletContext.setAttribute(          WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);//      添加初始化器      builder.initializers(new ParentContextApplicationContextInitializer(parent));    }    builder.initializers(        new ServletContextApplicationContextInitializer(servletContext));//    设置web上下文的类 AnnotationConfigEmbeddedWebApplicationContext    builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);    builder = configure(builder);//    添加监听器    builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));//    构建spring应用    SpringApplication application = builder.build();//    找到有@Configuration注解的类    if (application.getSources().isEmpty() && AnnotationUtils        .findAnnotation(getClass(), Configuration.class) != null) {      application.getSources().add(getClass());    }    Assert.state(!application.getSources().isEmpty(),        "No SpringApplication sources have been defined. Either override the "            + "configure method or add an @Configuration annotation");    // Ensure error pages are registered    if (this.registerErrorPageFilter) {      application.getSources().add(ErrorPageFilterConfiguration.class);    }//    启动spring boot应用程序    return run(application);  }

org.springframework.boot.web.support.SpringBootServletInitializer#run 运行SpringApplication程序

protected WebApplicationContext run(SpringApplication application) {    return (WebApplicationContext) application.run();  }

org.springframework.boot.SpringApplication#run(java.lang.String...)

public ConfigurableApplicationContext run(String... args) {    StopWatch stopWatch = new StopWatch();    stopWatch.start();    ConfigurableApplicationContext context = null;    FailureAnalyzers analyzers = null;    configureHeadlessProperty();//    初始化SpringApplicationRunListener -》    SpringApplicationRunListeners listeners = getRunListeners(args);//    执行EventPublishingRunListener监听器,广播应用启动事件    listeners.starting();    try {      ApplicationArguments applicationArguments = new DefaultApplicationArguments(          args);//      准备环境      ConfigurableEnvironment environment = prepareEnvironment(listeners,          applicationArguments);//      打印banner      Banner printedBanner = printBanner(environment);//      初始化spring上下文 -》      context = createApplicationContext();      analyzers = new FailureAnalyzers(context);//      准备spring上下文 -》      prepareContext(context, environment, listeners, applicationArguments,          printedBanner);//      刷新spring上下文 -》      refreshContext(context);//      spring上下文初始化完毕加载其他applicationRunner      afterRefresh(context, applicationArguments);//      执行监听器spring加载完成事件      listeners.finished(context, null);      stopWatch.stop();      if (this.logStartupInfo) {        new StartupInfoLogger(this.mainApplicationClass)            .logStarted(getApplicationLog(), stopWatch);      }      return context;    }    catch (Throwable ex) {      handleRunFailure(context, listeners, analyzers, ex);      throw new IllegalStateException(ex);    }  }

这个方法前面介绍过了

private ApplicationContext getExistingRootWebApplicationContext(      ServletContext servletContext) {    Object context = servletContext.getAttribute(        WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);    if (context instanceof ApplicationContext) {      return (ApplicationContext) context;    }    return null;  }

获得ApplicationContext

说在最后

本次解析仅代表个人观点,仅供参考。

1111a9e2551b5f2e5294be208bba1d49.gif

扫码进入技术微信群

3814be44efc59bc5da59a38219225c88.png 27cb72d0c787acafafb9bd3e01791c26.png fa3daac2ec44c4ca1517185d35cba8ee.png钉钉技术群

5d29db47368f31ad9b9ed273f97c164b.png

qq技术群

7b955990f55f0cb4c9e80cc9abbd5f31.png

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP