@SpringBootApplication你知多少?
我们都知道@SpringBootApplication注解是spring boot项目的启动注解。那么它具体表示什么含义呢,或者说都包含什么功能呢?接下来我们一探究竟。
一、解析@SpringBootApplication
SpringBootApplication是一个组合注解
(1)元注解
前四个是专门用于对注解进行注解的,称为元注解。
- @Target
- @Retention
- @Documented
- @Inherited:表示该注解会被子类自动继承。
(2)@SpringBootConfiguration
查看该注解的源码注解可知,该注解与@Configuration 注解功能相同,仅表示当前类为一个 JavaConfig 类,其就是为 Spring Boot 专门创建的一个注解。 所以,通常你会看到有人在启动类中使用@Bean注解生成一个实例对象。
(3)@ComponentScan
用于完成组件(@Component,@Controller,@Service,@Repository)扫描。不过需要注意,其仅仅用于配置组件扫描指令,并没有真正扫描,更没有装配其中的类,这个真正扫描是由@EnableAutoConfiguration 完成的。
注意一点:Spring Boot1.x 版本中仅会扫描当前标注类所在包的子孙包,不会扫描标注类所在的包。但 Spring Boot2.x 版本中默认会扫描当前注解所标注类所在的包及其子孙包。
(4)@EnableAutoConfiguration
@EnableAutoConfiguration表示开启自动配置功能。@EnableXxx 注解一般用于开启某一项功能,是为了简化代码的导入,即使用了该类注解,就会自动导入某些类。所以该类注解是组合注解,一般都会组合一个@Import 注解,用于导入指定的多个类,而被导入的类一般分为三种:配置类、选择器,与注册器。@import注解中导入的类可以认为是具体的配置功能实现类,也可以理解为是框架内部需要使用的Bean。
举例说明@Import导入类(了解):
A、配置类
@Import 中指定的类一般以 Configruation 结尾,且该类上会注解@Configuration,表示当前类为一个配置类。
B、选择器
@Import 中指定的类一般以 Selector 结尾,且该类实现了 ImportSelector 接口,表示当前类会根据条件选择要导入的类。
C、注册器
@Import 中指定的类一般以 Registrar 结尾,且该类实现了 ImportBeanDefinitionRegistrar接口,用于导入注册器,该类可以在代码运行时动态注册指定类的实例。
(5)引申(了解)
@import、@ImportResource、@PropertySource三个注解都是用于导入配置,有什么区别呢?
@import注解可以将普通类导入到spring容器中做管理;
@ImportResource(locations={}),与@import功能相似。只不过导入的是包含有definition配置的xml文件,而不是类。
@PropertySource可以导入property(key-value)文件到Spring容器中,用法:
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
二、解析@EnableAutoConfiguration
该注解用于开启自动配置,是 Spring Boot 的核心注解,是一个组合注解。所谓自动配置是指,其会自动找到其所需要的类,然后交给 Spring 容器完成这些类的装配。
- @Import:用于加载 Spring Boot 中内置的及导入 starter 中 META-INF/spring.factories配置中的自动配置类。
- @AutoConfigurationPackage:用于扫描、加载并注册自定义的组件类。
(1)@Import(AutoConfigurationImportSelector.class)
追踪 AutoConfigurationImportSelector的源码,我们可以发现确实是加载META-INF/spring.factories中的配置。
那么这个META-INF/spring.factories文件在哪里呢。所有的项目都依赖于spring-boot-starter,而spring-boot-starter又依赖于spirng-boot-autoconfigure,通过查看pom可以发现:
所以,我们在jar包中寻找spirng-boot-autoconfigure,
在spring.fatories中就看到一些默认的配置类,
key为org.springframework.boot.autoconfigure.EnableAutoConfiguration;
value为配置类全路径。
(2)@AutoConfigurationPackage
用于导入用户自定义类(即业务实现类),即自动扫描包中的类。
三、starter认知
通过以上的介绍,我们已经能够大致猜到在spring boot中是如何通过一个starter自动配置对象的了。
①通过@EnableAutoConfiguration读取到META-INF/spring.factories,这里边注册了所有需要加载的bean对应的配置类的全路径;
②spring会根据反射的原理,读取到配置类中使用@Bean声明的BeanDefinition,进而生成Bean对象放到IOC容器中。
通过以下两个例子我们再体会一下starter的配置。
(1)sping boot与redis整合
通过查看RedisAutoConfiguration,我们可以发现在此处创建了RedisTemplate实例。
(2)mybatis与spring boot整合
在 External Libraries 中找到 mybatis-spring-boot-starter 依赖。而该依赖又依赖于mybatis-spring-boot-autoconfigurigure。其 META-INF 中就有 spring.factories 文件,打开这个文件我们找到了 Mybatis 的自动配置类。
可以验证,我们以上的猜想starter=>spring.factories=>配置类=>生产Bean是正确的。
细心的人一定发现了以上有好多ConditionalOn开头的注解,它们是干什么用的呢?见名知意,没错,它们被称之为条件注解,只有符合注解条件时才会执行对应方法生成相应的Bean实例。
四、条件注解
常见的条件注解有:
@ConditionalOnClass():条件判断注解,其可以标注在类与方法上,表示当参数指定的类在类路径下存在时才会创建当前类的 Bean,或当前方法指定的 Bean。
@ConditionalOnMissionBean:条件判断注解,其可以标注在类与方法上,表示当容器中不存在当前类或方法类型的对象时,将去创建一个相应的 Bean。
@ConditionalOnBean():条件判断注解,其可以标注在类与方法上,表示当在容器中存在指定类的实例时才会创建当前类的 Bean,或当前方法指定的 Bean。
@ConditionalOnProperty():条件判断注解,其可以标注在类与方法上,表示配置文件中指定的属性满足条件时才会创建当前类的 Bean,或当前方法指定的 Bean。
五、手写一个starter
至此,我们应该可以手写一个starter了。可参考另一篇博客: