大概是水平有限,最近跟读代码与相关书籍感受巨费时间,想深刻弄明白全部的东西很难,因此也只能带着问题来学习springboot了,之后遇到确切的问题再作深刻了解把,给本身定个目标,暂时只弄清楚容器启动大致流程,了解组件扫描,自动配置,解决循环依赖这几个问题。 通常启动的Main方法为SpringApplication.run(启动类.class, args);
,跟下去的话会发现调用的就是new SpringApplication(启动类).run(args)因为容器刷新内容最关键也最复杂,先来了解下除容器刷新以外的流程。java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //一般状况下primarySources就是启动类,暂时理解这里就是将启动类设置为主配置资源来源 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //经过类路径中寻找相关类,判断当前环境是NONE(标准环境(classPath下没有javax.servlet.Servlet以及org.springframework.web.context.ConfigurableWebApplicationContext)、SERVLET(Servlet环境)、REACTIVE(响应式) this.webApplicationType = WebApplicationType.deduceFromClasspath(); //添加initializers,设置初始化器,这些初始化器将在在容器刷新前回调,原理是经过SpringFactoriesLoader的loadFactoryNames方法在 spring.factories文件中找到的ApplicationContextInitializer接口的配置的实现类的全限定类名,并实例化。 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //同上,设置ApplicationListener,添加 spring.factories文件中ApplicationListener配置的响应实现类。 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //经过构造一个运行时异常,而后去栈帧中寻找方法名为main的方法来获得入口类的名字并设置为mainApplicationClass this.mainApplicationClass = deduceMainApplicationClass(); }
debug发现有这些:web
他们的做用是:spring
debug发现有这些:编程
他们的做用是:缓存
REACTIVE是响应式编程的东西,指的是应用WebFlux框架下的应用环境,是NIO同步非阻塞IO,将来可能替代当前的MVC,因为是比较新的技术,应用场景比较有限,暂时不作深刻了解。springboot
public ConfigurableApplicationContext run(String... args) { //这个组件是用来监控启动时间的,不是很重要 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; //SpringBootExceptionReporter这个东西是一个异常解析器,实现类只有一个是FailureAnalyzers, //用于打印异常信息,这个集合在下面③处会初始化,集合里面装了针对各式各样的解析器, //在catch到异常后,会遍历这个集合,寻找合适的解析器,而后打印异常日志 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //刷新系统属性java.awt.headless的值,若是没有值则设为true,这个值表示无头模式(意指缺乏显示设备,键盘或鼠标的系统配置), //在无头模式下java.awt.Toolkit将使用特定的无头模式下的实现类,由于就算没有显示设备,有些操做任可以被容许。 configureHeadlessProperty(); //① SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { //② ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //配置系统参数spring.beaninfo.ignore,默认值为ture,字面意思是跳过搜索BeanInfo类,但具体是什么我暂时也不清楚。 configureIgnoreBeanInfo(environment); //③ Banner printedBanner = printBanner(environment); //④ context = createApplicationContext(); //⑤ exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); //⑥ prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); //刷新后的处理,是个空实现 afterRefresh(context, applicationArguments); //计时器结束 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //发布started事件 listeners.started(context); //运行器回调,即实现了ApplicationRunner接口或CommandLineRunner接口的bean callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
内部又是调getSpringFactoriesInstances方法,取spring.factories中全部的SpringApplicationRunListener,而后对外暴露SpringApplicationRunListeners。 SpringApplicationRunListeners封装全部的SpringApplicationRunListener,用于容器启动间的事件发布到全部的SpringApplicationRunListener中。app
SpringApplicationRunListener中定义的方法有:框架
值得注意的是,started、running、failed方法是 SpringBoot2.0 才加入的。less
经过Debug,发现默认状况下加载的listeners有一个,类型为 EventPublishingRunListener。它在SpringBoot应用启动的不一样时间点发布不一样应用事件类型(ApplicationEvent),若是有哪些事件监听者(ApplicationListener)对这些事件感兴趣,则能够接收而且处理。SpringApplicationRunListener与ApplicationListener的区别是SpringApplicationRunListener比ApplicationListener更靠前,SpringApplicationRunListener监听的是SpringApplication相关方法的执行,属于第一层监听器,他会发布相应的事件给ApplicationListener。学习
根据不一样的webApplicationType完成Environment的初始化,通常是使用StandardServletEnvironment实现类,Environment用于描述应用程序当前的运行环境,其抽象了两个方面的内容:配置文件(profile)和属性(properties),其实就是对应的配置文件、环境变量、命令行参数里面的内容。这里Environment构建完成时发布了environmentPrepared事件,而且将最新的配置值绑定到了SpringbootApplication中,也就是当前的对象中。好比yml里面配的spring. main开头的一些属性值。
根据Enviroment中配置获取对应的banners没有则用默认的SpringbootBanner打印启动信息,就是启动应用时候控制台打印的logo
根据WebApplicationType,反射建立不一样的ApplicationContext实现(Servlet是AnnotationConfigServletWebServerApplicationContext)。这里Servlet是AnnotationConfigServletWebServerApplicationContext,在他的父类GenericApplicationContext构造方法中,其中注入了一个DefaultListableBeanFactory,这个BeanFactory很关键,实际上AnnotationConfigServletWebServerApplicationContext的BeanFactory能力就是从DefaultListableBeanFactory扩展而来。 另外在这一步中也注册了ConfigurationClassPostProcessor、DefaultEventListenerFactory、EventListenerMethodProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor这些beanDefinition,做为基础组件。ConfigurationClassPostProcessor这个组件是最重要的,其余的暂时没有深究什么做用,ConfigurationClassPostProcessor是BeanFactoryPostProcessor,负责在容器刷新时加载扫描配置类注解进行组件解析,注册BeanDefinition。
建立一系列SpringBootExceptionReporter,建立流程是经过SpringFactoriesLoader获取到全部实现SpringBootExceptionReporter接口的class,
初始化ApplicationContext,主要完成如下工做:
容器刷新前,整个流程分三个步骤: