微服务 SpringBoot 2.0(三):启动剖析之@SpringBootApplication
2018-09-24 20:38
1881 查看
我原以为就一个注解,背后竟然还有3个 —— Java面试必修
引言
前面两章我们先后认识了SpringBoot和它的极简配置,为新手入门的学习降低了门槛,会基本的使用后,接下来我们将进一步认识SpringBoot,它为何能做到服务秒开,就来跟随我一起分析SpringBoot运行启动的原理吧。启动原理分2章讲解,本章讲解
@SpringBootApplication注解部分,若需了解SpringApplication.run方法部分请点击此处
运行启动
工具
SpringBoot版本:2.0.4开发工具:IDEA 2018
Maven:3.3 9
JDK:1.8
首先我们看一段启动代码
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
这不就是个启动类嘛?从字面理解我都知道Spring启动的入口,有啥好看的。可别小瞧了这几行代码
开始推理
从上面代码来看,@SpringBootApplication和
SpringApplication.run长得很相似,比较诡异,所以我们从这两个开始分析,首先先看注解
@SpringBootApplication
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { ... }
不要被那么多元注解声明所吓到,仔细查看可以看出其中有3个重要的注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
所以我觉得,这3个才是真正的幕后主使,
@SpringBootApplication只是他们找来挡枪口的,他们合体应该等价于
@SpringBootApplication,如下代码正常运行
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
哈哈,经过查询资料发现,Spring Boot 1.2版之前,真的是由这3个注解出面,之后呢,才隐居幕后,由小喽喽在前面挡枪
@SpringBootConfiguration
首先我们来分析这个,点开看到源码之后我慌了,这特么什么都没有,唯一的疑点在@Configuration。
好吧,还挺会伪装,我们就分析
@Configuration这个注解吧
用之前spring的思维,我推断这个应该是解决当前Class的XML配置问题,凡是经过该注解修饰的,均被实例化到Spring应用程序上下文中,由spring统一管理生命周期,我说IoC大家应该熟悉了吧。
举个例子
传统的XML配置对象的写法
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init="true"> <!--bean定义--> <bean id="userService" class="..UserServiceImpl"> ... </bean> </beans>
使用
@Configuration之后的写法
@Configuration public class SpringConfiguration{ @Bean public UserService userService(){ return new UserServiceImpl(); } }
任何一个标注了
@Configuration的Java类定义都是一个JavaConfig配置类。
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。
表达依赖注入关系层面
<bean id="userService" class="..UserServiceImpl"> <propery name ="dependencyService" ref="dependencyService" /> </bean> <bean id="dependencyService" class="DependencyServiceImpl"></bean>
@Configuration public class SpringConfiguration{ @Bean public UserService userService(){ return new UserServiceImpl(dependencyService()); } @Bean public DependencyService dependencyService(){ return new DependencyServiceImpl(); } }
如果一个bean的定义依赖其他bean,则直接调用对应的JavaConfig类中依赖bean的创建方法即可,如上方的
dependencyService()。
@ComponentScan
这个注解在Spring中很重要,它对应XML配置中的元素,
@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如
@Component和
@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过
basePackages等属性来细粒度的定制
@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明
@ComponentScan所在类的package进行扫描。
以前xml中是这么定义的,如下
<context:component-scan base-package="com.platform.fox.html.**.controller"/> <context:component-scan base-package="com.platform.fox.html.**.repository"/> <context:component-scan base-package="com.platform.fox.html.**.service"/> <context:component-scan base-package="com.platform.fox.html.**.wshandler"/>
注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定
basePackages。
@EnableAutoConfiguration
Enable,通常来说我们认为它一定是在开启或者支持什么功能,比如:
@EnableScheduling、
@EnableCaching,所以他们要做的事情应该都是相似的,根据源码判断,简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。
@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 {}; }
我理解就是要开船了,
EnableAutoConfigurationImportSelector根据名单把水手,舵手、安检员都统一叫过来各就各位。帮助SpringBoot应用将所有符合条件的
@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一管理员一样
借助于Spring框架原有的一个工具类:
SpringFactoriesLoader的支持,
@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!
EnableAutoConfigurationImportSelector中自动配置的关键方法如下
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //获取符合条件的带有Configuration的注解示例类 List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; }
SpringFactoriesLoader
所以真正的工作者是
SpringFactoriesLoader,
SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件
META-INF/spring.factories加载配置
public abstract class SpringFactoriesLoader { //... public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) { ... } public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { .... } }
配合
@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据
@EnableAutoConfiguration的完整类名
org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类
spring.factories
上图就是从
SpringBoot的autoconfigure依赖包中的
META-INF/spring.factories配置文件中摘录的一段内容,可以很好地说明问题。我从中随机挑取一个类查看源代码
WebMvcAutoConfiguration
所以,其底层真正实现是从classpath中搜寻所有的
META-INF/spring.factories配置文件,并将其中
org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。
@SpringBootApplication注解说完了,接下来我们来分析
SpringApplication.run方法
作者有话说:喜欢的话就请关注Java面试必修 ,请自备水,更多干、干、干货等着你
相关文章推荐
- IDEA启动Spring Boot项目提示Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServlet...
- Cas之5.2.x版本之单点登录服务安装(SpringBoot启动)-yellowcong
- Spring Boot 2.0(七):Spring Boot 如何解决项目启动时初始化资源
- springboot使用Application启动失败,bootrun启动成功
- spring boot-1.4.2 jar启动使用外部application.properties
- Spring boot源码分析-AnnotationConfigApplicationContext非web环境下的启动容器(2)
- 从eclipse中导入到IDEA中的SpringBoot项目,启动时报错 Unable to start EmbeddedWebApplicationContext due to missing Em
- Spring Boot 2.0(七):Spring Boot 如何解决项目启动时初始化资源
- SpringBoot启动报错 ApplicationStartingEvent,刚入门使用springboot
- spring boot注册成linux服务时,启动参数RUN_ARGS的输入
- Java问题解决:springboot启动出现-Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package
- spring boot/cloud 多服务部署单机启动顺序有依赖的解决办法
- 【SFA官方翻译】使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南
- Spring boot2.0 启动报错 java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
- Springboot启动报错:Your ApplicationContext is unlikely to start due to a @ComponentScan of the default
- 关于springboot启动时候报错:springboot Failed to parse configuration class [Application]
- spring boot 集成quartz 2.0 实现前端动态配置(获取spring上下文)的两种方式,启动数据库中已开启定时任务
- spring-boot服务启动报: Unable to start embedded container
- SpringCloud SpringBoot mybatis 分布式微服务(十九)springboot在启动时注入了哪些bean
- IDEA启动spring boot 出现Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCont