AI智能
改变未来

SpringBoot源码解析


SpringBoot源码解析

我们启动SpringBoot的代码:

@SpringBootApplicationpublic class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}}

我们主要从3大点着手解析:

  • @SpringBootApplication注解
  • 构建SpringApplication对象
  • SpringApplication的run方法

@SpringBootApplication解析

我们来看看SpringBootApplication的注解的代码:

@Target(ElementType.TYPE)    //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举中@Retention(RetentionPolicy.RUNTIME) ///表示注解的生命周期,Runtime运行时@Documented ////表示注解可以记录在javadoc中@Inherited   //表示可以被子类继承该注解@SpringBootConfiguration //// 标明该类为配置类@EnableAutoConfiguration  // 启动自动配置功能@ComponentScan(excludeFilters = {   // 包扫描器 <context:component-scan base-package="com.xxx.xxx"/>@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication

排除掉上面的4个元注解外,还剩下3个注解,我们一一分析。

  1. @SpringBootConfiguration

这个里面什么都没有,就只是在这个注解上标明了@Configuration,代表是一个配置类。2. @EnableAutoConfiguration

这个注解主要是启动自动配置功能,我们点进去详细看看。

@AutoConfigurationPackage		//自动配置包 : 会把@springbootApplication注解标注的类所在包名拿到,并且对该包及其子包进行扫描,将组件添加到容器中@Import(AutoConfigurationImportSelector.class)  //可以帮助springboot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器(ApplicationContext)中public @interface EnableAutoConfiguration {

2.1 我们先看@AutoConfigurationPackage注解

@Import(AutoConfigurationPackages.Registrar.class)  //  默认将主配置类(@SpringBootApplication)所在的包及其子包里面的所有组件扫描到Spring容器中public @interface AutoConfigurationPackage {}

可以看出主要是引入了Registrar这个类,继续跟踪Registrar这个类

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {// 获取的是项目主程序启动类所在的目录//metadata:注解标注的元数据信息@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {//默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件register(registry, new PackageImport(metadata).getPackageName());}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImport(metadata));}}

主要目的获取SpringBoot主程序启动类的包名并注册

2.2 继续看@Import(AutoConfigurationImportSelector.class)

@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {//判断 enableautoconfiguration注解有没有开启,默认开启(是否进行自动装配)if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}//1. 加载配置文件META-INF/spring-autoconfigure-metadata.properties,从中获取所有支持自动配置类的条件//作用:SpringBoot使用一个Annotation的处理器来收集一些自动装配的条件,那么这些条件可以在META-INF/spring-autoconfigure-metadata.properties进行配置。// SpringBoot会将收集好的@Configuration进行一次过滤进而剔除不满足条件的配置类// 自动配置的类全名.条件=值AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

主要是获取并筛选出自动配置类并返回。

  1. @ComponentScan

这个注解就是包扫描的作用,类似Spring里面的:

<context:component-scan base-package="com.xxx.xxx"/>

构建SpringApplication对象

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.sources = new LinkedHashSet();this.bannerMode = Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.addConversionService = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();this.isCustomEnvironment = false;this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");//项目启动类 SpringbootDemoApplication.class设置为属性存储起来this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//设置应用类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 设置初始化器(Initializer),最后会调用这些初始化器//所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,在Spring上下文被刷新之前进行初始化的操作setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置监听器(Listener)setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 初始化 mainApplicationClass 属性:用于推断并设置项目main()方法启动的主程序启动类this.mainApplicationClass = deduceMainApplicationClass();}

run方法

public ConfigurableApplicationContext run(String... args) {// 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长。StopWatch stopWatch = new StopWatch();stopWatch.start();// 初始化应用上下文和异常报告集合ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();// 配置 headless 属性configureHeadlessProperty();//   (1)获取并启动监听器SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {// 创建  ApplicationArguments 对象 初始化默认应用参数类// args是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。如:--server.port=9000ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//(2)项目运行环境Environment的预配置// 创建并配置当前SpringBoot应用将要使用的Environment// 并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);// 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体Banner printedBanner = printBanner(environment);// (3)创建Spring容器context = createApplicationContext();// 获得异常报告器 SpringBootExceptionReporter 数组//这一步的逻辑和实例化初始化器和监听器的一样,// 都是通过调用 getSpringFactoriesInstances 方法来获取配置的异常类名称并实例化所有的异常处理类。exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// (4)Spring容器前置处理//这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。prepareContext(context, environment, listeners, applicationArguments,printedBanner);// (5):刷新容器refreshContext(context);// (6):Spring容器后置处理//扩展接口,设计模式中的模板方法,默认为空实现。// 如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理afterRefresh(context, applicationArguments);// 停止 StopWatch 统计时长stopWatch.stop();// 打印 Spring Boot 启动的时长日志。if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// (7)发出结束执行的事件通知listeners.started(context);// (8):执行Runners//用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序//Runner 运行器用于在服务启动时进行一些业务初始化操作,这些操作只在服务启动后执行一次。//Spring Boot提供了ApplicationRunner和CommandLineRunner两种服务接口callRunners(context, applicationArguments);} catch (Throwable ex) {// 如果发生异常,则进行处理,并抛出 IllegalStateException 异常handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}//   (9)发布应用上下文就绪事件//表示在前面一切初始化启动都没有问题的情况下,使用运行监听器SpringApplicationRunListener持续运行配置好的应用上下文ApplicationContext,// 这样整个Spring Boot项目就正式启动完成了。try {listeners.running(context);} catch (Throwable ex) {// 如果发生异常,则进行处理,并抛出 IllegalStateException 异常handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}//返回容器return context;}
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » SpringBoot源码解析