引言
- 在引入 Spring Boot 框架之后,省去了 xml 文件配置可以理解为注解体系的不断完善,但省去的依赖的管理, Spring Boot 框架是如何做到的?
- 我们返回启动类,观察其中代码
这其中有两个关键的地方值得研究
- 注解:@SpringBootApplication
- run方法:SpringApplication.run()
对于注解 @SpringBootApplication
- 查看 @SpringBootApplication 源码
这里重点的注解有3个
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
- 查看 @SpringBootConfiguration 源码
解读:
- 可以看到,这个注解上面,又有一个 @Configuration 注解
- 通过上面的注释了解到:这个注解的作用就是声明当前类是一个配置类,然后 Spring 会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息
- 而 @SpringBootConfiguration 是来声明当前类是SpringBoot应用的配置类,项目中只能有一个,所以一般我们无需自己添加
- 查看 @EnableAutoConfiguration 源码
解读
- 插入一段官方说明: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.
- 简单翻译为:第二级的注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了
- 结合源码内注释,大概得出结论,Spring Boot 内部对大量的第三方库及 Spring 内库进行了默认配置,并且会根据我们在创建项目时候的风格,是否引入了对应库的依赖等来判断哪些配置可能会被使用到,这些默认配置就会生效
- 所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了,若你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口
- 查看 @ComponentScan 源码
解读:
- 注释大概意思:配置组件扫描的指令。提供了类似与< context:component-scan >标签的作用,通过 basePackageClasses 或者 basePackages 属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
- 我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包
- 因此,启动类在项目目录结构中,一般都会处于较浅层的位置,以便于扫描
对于 SpringApplication.run() 方法
-
点击查看源码中方法
/** * 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; } -
观察源码中执行的步骤大概分为
- 初始化监听器
- 发布ApplicationStartingEvent
- 装配参数和环境
- 发布ApplicationEnvironmentPreparedEvent
- 创建ApplicationContext,并装配
- 发布ApplicationPreparedEvent
- 发布ApplicationStartedEvent
- 执行Spring中@Bean下的一些操作,如静态方法等
- 发布ApplicationReadyEvent