zoukankan      html  css  js  c++  java
  • SpringBoot的启动

    主要是SpringApplication.run()方法,其中准备环境和刷新context里有比较关键的部分
    分析的项目是用的 gs-routing-and-filtering 下的complete/gateway-0.0.1-SNAPSHOT

    1 获取SpringApplicationRunListeners,广播start事件

    2 准备环境

    3 打印spring的banner.

    4.创建 AnnotationConfigEmbeddedWebApplicationContext

    5 准备AnnotationConfigEmbeddedWebApplicationContext

    6 刷新AnnotationConfigEmbeddedWebApplicationContext

    7.刷新后进行的调用,主要是ApplicationRunner和CommandLineRunner

    8.发布完成事件

    2 准备环境

    不监听bootstrap context的ApplicationEnvironmentPreparedEvent,即environment的getPropertySources()里有bootstrap就直接返回,否则就创建bootstrapServiceContext().

    在准备环境时,如果没有会创建一个bootstrap的context,并设置为应用context的父,一些bootstrap需要使用到的bean,在创建bootstrap context的时候的refresh里会创建即实例化,bootstrap context类型为ConfigurableApplicationContext,创建完成后准备环境会返回StandardEnvironment,准备环境完成.

    创建 ConfigurableApplicationContext   
    ConfigurableApplicationContext context = bootstrapServiceContext (environment,event.getSpringApplication());
    
    使用SpringApplicationBuilder.run()创建ConfigurableApplicationContext对象,这会再调用SpringApplication.run().这次prepareEnvironment会直接返回之前已创建的StandardEnvironment.
    
    createApplicationContext()会创建 AnnotationConfigApplicationContext.
    
    prepareContext()会调用applyInitializers()进行refresh之前的各种初始化操作.
      
    监听器发布AnnotationConfigApplicationContext的contextPrepared事件.
    把bean加载到context里,load几个Configuration类.
    refreshContext;
    告诉子类刷新内部的BeanFactory,准备这个context使用的BeanFactory,设置beanFactory的回调,注册resolvable依赖,注册默认的环境beans.
    
    factory processors注册到context里,注册bean创建时的拦截器bean processors,初始化MessageSource.初始化ApplicationEventMulticaster.初始化其他的特别子类的特别的bean,注册监听器.实例化所有的剩余的(不是懒加载的)单例对象.完成refresh,初始化lifecycle processor,告诉lifecycle processor onRefresh,发布ContextRefreshedEvent事件.重置common introspection caches,因为单例对象可能再也用不到这些缓存的元数据.刷新后调用runners.调用SpringApplicationRunListeners完成事件.
    设置bootstrap context成为应用context的一个父类.
    广播ApplicationEnvironmentPreparedEvent 事件.环境准备完毕
    

    6 刷新AnnotationConfigEmbeddedWebApplicationContext

    具体看AbstractApplicationContext.refresh(),扫描项目包里用户定义的.class文件,然后进行bean定义和实例化也在这一步里面.spring里有着大量的Listener,他们通过Multicaster来广播某一个event来让特殊的listener做指定的处理.

    准备这个context使用的beanfactory
    
    invokeBeanFactoryPostProcessors(beanFactory)调用工程处理器在context里注册为bean.扫描用户配置的bean也是在这一步里.
    ConfigurationClassParser.processConfigurationClass(configurationClass);
    递归处理ConfigurationClass,和它的父类.
    
    ClassPathBeanDefinitionScanner.doScan()
    扫描项目包,返回BeanDefinitionHolder.默认扫描的路径是@SpringBootApplication的为根目录.
    
    这里需要注意的是扫描class文件解析后生成的是BeanDefinition,有了这个就可以创建bean对象,但是此时对象并没有生成.
    最后发布ContextRefreshedEvent事件
    
    刷新后重置spring通用缓存
    
    发布ApplicationReadyEvent事件
    

    AbstractApplicationContext.refresh()的代码:

    public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// Register bean processors that intercept bean creation.
    				registerBeanPostProcessors(beanFactory);
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				finishBeanFactoryInitialization(beanFactory);
    
    				// Last step: publish corresponding event.
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
    
    				// Destroy already created singletons to avoid dangling resources.
    				destroyBeans();
    
    				// Reset 'active' flag.
    				cancelRefresh(ex);
    
    				// Propagate exception to caller.
    				throw ex;
    			}
    
    			finally {
    				// Reset common introspection caches in Spring's core, since we
    				// might not ever need metadata for singleton beans anymore...
    				resetCommonCaches();
    			}
    		}
    	}
    

    BeanDefinition与Bean的一些概念:

    BeanDefinition描述一个有属性值,,有构造参数值,和提供给具体实现使用的进一步信息的bean实例.这只是一个最小化的接口:主要目的是允许比如PropertyPlaceholderConfigurer这样的BeanFactoryPostProcessor来内省和修改属性值和其他bean的元数据.
    BeanWrapper:spring底层级别的javabean设施的的核心接口,通常不直接使用,会通过BeanFactory或者DataBinder来使用.
    
    AttributeAccessor定义一个可以从任意对象里获取设置元数据的一般协议.
    
    BeanMetadataElement一个bean的元数据元素用来实现携带一个configuration源对象.
    
    AbstractBeanDefinition是具体的,完整的BeanDefinition类的基础类.是GenericBeanDefinition,RootBeanDefinition和ChildBeanDefinition的分解公共属性.
    
    GenericBeanDefinition是一个一站式的标准bean定义.和任何bean定义一样,它允许指定一个类加可选的构造参数值和属性值.另外,通过`parentName`属性从一个父bean定义获取可以被灵活配置.总的来说,使用GenericBeanDefinition时为了注册用户可见的bean定义(一个post-processor可能对其操作,甚至有重新配置the parent name的可能).当父子关系预先决定了就可以使用RootBeanDefinition / ChildBeanDefinition . GenericBeanDefinition是自2.5以后新加入的bean文件配置属性定义类,是ChildBeanDefinition和RootBeanDefinition更好的替代者.
    
    RootBeanDefinition表示在运行时,一个支持在spring BeanFactory支持一个特定bean的合并的bean定义.它可能被多个源bean定义互相继承中创建.典型地注册为GenericBeanDefinition.根本上来说,在运行时一个RootBeanDefinition是一个统一的bean定义视图
    
    ChildBeanDefinition定义那些从父类继承配置的bean.子bean定义对父bean定义有一个固定的依赖.
    
    AnnotatedBeanDefinition暴露一个关于bean定义的类的注解元数据,在不要求类加载的情况下.
    
    AnnotatedGenericBeanDefinition类继承GenericBeanDefinition抽象类,通过实现AnnotatedBeanDefinition接口支持暴露注解元数据信息。 注意:GenericBeanDefinition 变体主要用于测试代码(希望对AnnotatedBeanDefinition 进行操作),例如Spring组件的扫描支持的实现类(默认类是ScannedGenericBeanDefinition,通常也实现AnnotatedBeanDefinition接口).
    
    ScannedGenericBeanDefinition这个类不早早的加载bean的类.它倾向于从".class"文件里获取所有相关的元数据,使用ASM ClassReader解析.它的功能和AnnotatedGenericBeanDefinition#AnnotatedGenericBeanDefinition(AnnotationMetadata)相同,但是被已经扫描过得类型bean和那些已经被别的注册或者发现为其他意义的beans区分.
    

    创建一个bean的过程

    //运行Spring应用,创建和刷新一个新的ApplicationContext
    SpringApplication.run();
    SpringApplication.refreshContext();
    //实例化并调用所有注册的BeanFactoryPostPrcessor beans,如果有明确的顺序就按顺序来.必须在单例对象实例化之前调用.
    AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory);
    PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
    //构建和校验一个基于注册的Configuration类的配置模型
    ConfigrationClassPostProcessor.processConfigBeanDefinitions(registry);
    //通过从源类里读取注解,成员和方法来处理和构建一个完整的ConfigurationClass.当相关的源被发现时这个方法可以被调用多次,返回处理类的父类,没有就返回null.
    ConfigurationClassParser.doProcessConfigurationClass(configClass, sourceClass)
    /**内部逻辑:(加载类定义的顺序)
    首先递归的处理所有的成员(包括内嵌的);
    处理所有的@PropertySource注解;
    处理所有的@ComponentScan注解;
    处理所有的@Import注解;
    处理所有的@ImportResource注解;
    处理单独的@Bean方法;
    处理接口的默认方法;
    如果有父类处理父类,发现父类就返回父类的注解元数据然后递归;
    没有父类就处理完成;
    */
    
    //对指定的基础包进行一个扫描,返回所有的注册bean定义.这个方法不注册任何注解配置处理器,把这留给调用者来处理.
    ClassPathBeanDefinitionScanner.doScan(basePackages)
    /**内部逻辑:
    扫描包获取候选的bean定义;
    若是AbstractBeanDefinition,进一步的设置给的bean定义,超越从扫描的组件类里获取的内容;
    若是AnnotatedBeanDefinition,把元数据里的注解转换成bean定义里的设置;
    校验beanName是否和相关的bean定义需要注册或者和一个已存在的定义有冲突.
    创建bean定义的持有者;bean的持有者是否需要代理;注册bean的持有者.
    */
    
    //为候选的组件扫描类路径(把org.springframework.context.annotation. ClassPathBeanDefinitionScanner 设置为trace可以输出扫描的路径,忽略的资源,设置为debug可以打印被认证的组件类或者被忽视的类)
    ClassPathBeanDefinitionScanner.findCandidateComponents(basePackage)
    /**
    内部逻辑:
      //决定给的类是否匹配任何的排除过滤器或者至少匹配一个包含过滤器.
      ClassPathScanningCandidateComponentProvider.isCandidateComponet(metadataReader)
      //根据metadataReader描述的类,创建一个新的ScanneedGebericBeanDefinition.
      new ScannedGenericBeanDefinition(metadataReader)
      //决定被给的bean定义是否有作为候选的资格.默认的方法实现检查了类是否是具体的(也就是非抽象或者接口).也检查了被描述的类是否是独立的类,也就是说是top-level类还是可以从封装类里被独立构建的内嵌类(静态内部类).
      ClassPathScanningCandidateComponentProvider. isCandidateComponet(AnnotatedBeanDefinition)
    */
     
    //在当前的beanFactory里找寻AspectJ注解的切面bean,返回一个Advisor的list来表示他们
    BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors();
    
    
    

    创建对象相关的调用方法

    AbstractAutowireCapableBeanFactory.instantiateBean(beanName,mbd)

    创建对象

    AbstractAutowireCapableBeanFactory.initializeBean(beanName,bean,mbd)

    初始化对象

    AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(existingBean,beanName);创建完成之前的处理,会对Aware进行设置

    DefaultListableBeanFactory.preInstantiateSingletons();

    实例化所有剩余的单例bean

    启动tomcat

    在AnnotationConfigEmbeddedWebApplicationContext刷新时会调用EmbeddedWebApplicationContext.onRefresh()的方法,这会创建容器,在这个项目里就是创建一个内嵌的tomcat.tomcat启动时会实例化ServletContextInitializer,在本项目中ZuulFilterInitializer就是一个ServletContextInitializer的子类.该类的初始化,会把ZuulFilter都实例化,包括项目中的SimpleFilter.

    EmbeddedWebApplicationContext.createEmbeddedServletContainer();
    
    ContainerBase.startInternal()
    启动这个组件,实现要求的接口
    ContainerBase.findChildren()
    找到这个容器关联的子容器,把子容器放到另一个线程池里执行
    ContainerBase.StartChild.call();
    
    调用子容器StandardEngine.start();
    
    StandardHost.startInternal();
    
    TomcatStarter.onStartup(classes,servletContext);
    EmbeddedWebApplicationContext.getServletContextInitializerBeans()
     
    获取embedded Servlet context需要使用的ServletContextInitializer们
    这里会实例化类型为ServletContextListener的bean,所以ZuulFilterInitializer会在这里被实例化.SimpleFilter会在Initializer里被实例化.这是一些底层处理器的实例化时机,比普通的bean要实例化的早
    
    

    springboot启动小结

    springboot里我比较关心的就是对象是如何创建的.在refresh里扫描class文件,转换成beanDefinition.再在需要的时候实例化.实例化时,所依赖的对象会先实例化,这里面经常会采用递归的方式来遍历创建bean.最后再把一些没有在初始化里创建的bean通过finishBeanFactoryInitialization来创建.

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);
    
  • 相关阅读:
    洛谷P2124 奶牛美容
    UVA10325 The Lottery
    CF979C Kuro and Walking Route
    洛谷P4318 完全平方数(莫比乌斯函数)
    hdu2204 Eddy's爱好(莫比乌斯函数)
    LOJ#6053. 简单的函数(min_25筛)
    洛谷P5325 【模板】Min_25筛
    超级码力在线编程大赛初赛 第3场 2.房屋染色
    超级码力在线编程大赛初赛 第3场 3.字符串游戏(Anti-Nim)
    超级码力在线编程大赛初赛 第3场 1.最大公倍数
  • 原文地址:https://www.cnblogs.com/saias/p/9152473.html
Copyright © 2011-2022 走看看