引言
  1. 在引入 Spring Boot 框架之后,省去了 xml 文件配置可以理解为注解体系的不断完善,但省去的依赖的管理, Spring Boot 框架是如何做到的?
  2. 我们返回启动类,观察其中代码
    Spring Boot 【四、自动配置原理】

这其中有两个关键的地方值得研究

  1. 注解:@SpringBootApplication
  2. run方法:SpringApplication.run()
对于注解 @SpringBootApplication
  1. 查看 @SpringBootApplication 源码
    Spring Boot 【四、自动配置原理】

这里重点的注解有3个

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan
  1. 查看 @SpringBootConfiguration 源码
    Spring Boot 【四、自动配置原理】

解读:

  1. 可以看到,这个注解上面,又有一个 @Configuration 注解
  2. 通过上面的注释了解到:这个注解的作用就是声明当前类是一个配置类,然后 Spring 会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息
  3. 而 @SpringBootConfiguration 是来声明当前类是SpringBoot应用的配置类,项目中只能有一个,所以一般我们无需自己添加
  1. 查看 @EnableAutoConfiguration 源码
    Spring Boot 【四、自动配置原理】

解读

  1. 插入一段官方说明:The second class-level annotation is @EnableAutoConfiguration. This annotation tells Spring Boot to “guess” how you want to configure Spring, based on the jar dependencies that you have added. Since spring-boot-starter-web added Tomcat and Spring MVC, the auto-configuration assumes that you are developing a web application and sets up Spring accordingly.
  2. 简单翻译为:第二级的注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了
  3. 结合源码内注释,大概得出结论,Spring Boot 内部对大量的第三方库及 Spring 内库进行了默认配置,并且会根据我们在创建项目时候的风格,是否引入了对应库的依赖等来判断哪些配置可能会被使用到,这些默认配置就会生效
  4. 所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了,若你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口
  1. 查看 @ComponentScan 源码
    Spring Boot 【四、自动配置原理】Spring Boot 【四、自动配置原理】

解读:

  1. 注释大概意思:配置组件扫描的指令。提供了类似与< context:component-scan >标签的作用,通过 basePackageClasses 或者 basePackages 属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
  2. 我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包
  3. 因此,启动类在项目目录结构中,一般都会处于较浅层的位置,以便于扫描
对于 SpringApplication.run() 方法
  1. 点击查看源码中方法

     /**
      * Run the Spring application, creating and refreshing a new
      * {@link ApplicationContext}.
      * @param args the application arguments (usually passed from a Java main method)
      * @return a running {@link ApplicationContext}
      */
     public ConfigurableApplicationContext run(String... args) {
     	StopWatch stopWatch = new StopWatch();
     	stopWatch.start();
     	ConfigurableApplicationContext context = null;
     	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     	configureHeadlessProperty();
     	
     	//初始化监听器
     	
     	SpringApplicationRunListeners listeners = getRunListeners(args);
     	
     	//发布ApplicationStartingEvent
     	
     	listeners.starting();
     	try {
     	
     		//装配参数和环境
     		
     		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
     				args);
     				
     		//发布ApplicationEnvironmentPreparedEvent
     		
     		ConfigurableEnvironment environment = prepareEnvironment(listeners,
     				applicationArguments);
     		configureIgnoreBeanInfo(environment);
     		Banner printedBanner = printBanner(environment);
     		
     		//创建ApplicationContext,并装配
     		
     		context = createApplicationContext();
     		exceptionReporters = getSpringFactoriesInstances(
     				SpringBootExceptionReporter.class,
     				new Class[] { ConfigurableApplicationContext.class }, context);
     				
     		//发布ApplicationPreparedEvent
     		
     		prepareContext(context, environment, listeners, applicationArguments,
     				printedBanner);
     		refreshContext(context);
     		afterRefresh(context, applicationArguments);
     		stopWatch.stop();
     		if (this.logStartupInfo) {
     			new StartupInfoLogger(this.mainApplicationClass)
     					.logStarted(getApplicationLog(), stopWatch);
     		}
     		
     		//发布ApplicationStartedEvent
     		
     		listeners.started(context);
    
     		//执行Spring中@Bean下的一些操作,如静态方法等
     		
     		callRunners(context, applicationArguments);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, listeners);
     		throw new IllegalStateException(ex);
     	}
    
     	try {
     	
     		//发布ApplicationReadyEvent
     		
     		listeners.running(context);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, null);
     		throw new IllegalStateException(ex);
     	}
     	return context;
     }
    
  2. 观察源码中执行的步骤大概分为

    1. 初始化监听器
    2. 发布ApplicationStartingEvent
    3. 装配参数和环境
    4. 发布ApplicationEnvironmentPreparedEvent
    5. 创建ApplicationContext,并装配
    6. 发布ApplicationPreparedEvent
    7. 发布ApplicationStartedEvent
    8. 执行Spring中@Bean下的一些操作,如静态方法等
    9. 发布ApplicationReadyEvent

相关文章:

  • 2021-08-22
  • 2021-08-30
  • 2021-11-20
  • 2022-12-23
  • 2022-01-15
  • 2021-08-06
  • 2021-09-15
猜你喜欢
  • 2022-12-23
  • 2021-06-28
  • 2021-10-23
  • 2021-12-22
  • 2021-07-30
相关资源
相似解决方案