时间:2021-05-19
这篇文章主要介绍了通过代码实例了解SpringBoot启动原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
SpringBoot和Spring相比,有着不少优势,比如自动配置,jar直接运行等等。那么SpringBoot到底是怎么启动的呢?
下面是SpringBoot启动的入口:
@SpringBootApplicationpublic class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); }}一、先看一下@SpringBoot注解:
@Target({ElementType.TYPE}) //定义其使用时机@Retention(RetentionPolicy.RUNTIME) //编译程序将Annotation储存于class档中,可由VM使用反射机制的代码所读取和使用。@Documented //这个注解应该被 javadoc工具记录@Inherited //被注解的类会自动继承. 更具体地说,如果定义注解时使用了 @Inherited 标记,然后用定义的注解来标注另一个父类, 父类又有一个子类(subclass),则父类的所有属性将被继承到它的子类中.@SpringBootConfiguration //@SpringBootConfiguration就相当于@Configuration。JavaConfig配置形式@EnableAutoConfiguration@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class})} //自动扫描并加载符合条件的组件。以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。)public @interface SpringBootApplication { @AliasFor( annotation = EnableAutoConfiguration.class ) Class<?>[] exclude() default {}; @AliasFor( annotation = EnableAutoConfiguration.class ) String[] excludeName() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackages" ) String[] scanBasePackages() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackageClasses" ) Class<?>[] scanBasePackageClasses() default {};}所以,实际上SpringBootApplication注解相当于三个注解的组合,@SpringBootConfiguration,@ComponentScan和@EnableAutoConfiguration。
@SpringBootConfiguration和@ComponentScan,很容易知道它的意思,一个是JavaConfig配置,一个是扫描包。关键在于@EnableAutoConfiguration注解。先来看一下这个注解:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {};}Springboot应用启动过程中使用ConfigurationClassParser分析配置类时,如果发现注解中存在@Import(ImportSelector)的情况,就会创建一个相应的ImportSelector对象, 并调用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 这里 EnableAutoConfigurationImportSelector的导入@Import(EnableAutoConfigurationImportSelector.class) 就属于这种情况,所以ConfigurationClassParser会实例化一个 EnableAutoConfigurationImportSelector 并调用它的 selectImports() 方法。
AutoConfigurationImportSelector implements DeferredImportSelector extends ImportSelector。
下面是AutoConfigurationImportSelector的执行过程:
二、下面看一下SpringBoot启动时run方法执行过程
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); this.configureHeadlessProperty(); //从类路径下META-INF/spring.factories获取 SpringApplicationRunListeners listeners = getRunListeners(args); //回调所有的获取SpringApplicationRunListener.starting()方法 listeners.starting(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //创建环境完成后回调 SpringApplicationRunListener.environmentPrepared();表示环境准备完成 this.configureIgnoreBeanInfo(environment); //打印Banner图 Banner printedBanner = printBanner(environment); //创建ApplicationContext,决定创建web的ioc还是普通的ioc context = createApplicationContext(); //异常分析报告 exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //准备上下文环境,将environment保存到ioc中 //applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法 //listeners.contextPrepared(context) //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded() this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新容器,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat) //扫描,创建,加载所有组件的地方,(配置类,组件,自动配置) this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } //所有的SpringApplicationRunListener回调started方法 listeners.started(context); //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调, //ApplicationRunner先回调,CommandLineRunner再回调 this.callRunners(context, applicationArguments); } catch (Throwable ex) { this.handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //所有的SpringApplicationRunListener回调running方法 listeners.running(context); } catch (Throwable ex) { this.handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } //整个SpringBoot应用启动完成以后返回启动的ioc容器 return context;}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
前言对springboot本身启动原理的分析,请参考:Springboot里的ClassLoader继承关系可以运行下面提供的demo,分别在不同的场景下运行,
1、以servlet的方式启动SpringBoot正常情况下要复制代码到tomcat去启动,但springboot内置tomcat了,配置好就可以直接run方法
springboot设置默认首页,方法实验ok如下附上application启动代码?1234567891011121314151617181920212223
下面通过实例代码给大家介绍Tomcat解析XML和反射创建对象原理,具体代码如下所示:importjava.lang.reflect.InvocationTar
我们都知道springboot由于内置tomcat(中间件)直接用启动类就可以启动了。而且我们有时想代码给程序设置一些默认参数,所以使用方法Springboot