springboot是服务于spring框架的一个框架,它的作用就是帮我们简化配置,高效搭建一个spring项目,在spring的基础上最佳的实现了
“约定优于配置”
。
一、约定优于配置的主要体现
- maven的目录结构
- spring-boot-starter-web中默认包含springmvc相关依赖和配置,得以默认jar方式打包
- 默认提供application.properties/yml配置文件
- 默认通过spring.profiles.active来属性来决定使用运行时环境的配置文件
- EnableAutoConfituration默认对于依赖的starter进行自动装配
二、分析注解
@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 {
...
}
从以上得知
@SpringBootApplication
这个启动类注解其实是由:
@SpringBootConfiguration
(进入核心其实是@Configuration
)、
@EnableAutoConfiguration
、
@ComponentScan
三个注解组成,我们则可以接着往下分析这三个注解。
@Configuration
- Configuration这个注解在开发中使用较多,它是JavaConfig形式的基础Spring IOC容器配置管理的一种注解。
- 派生自@component注解。
- 所以在启动类里加了@Configuration意味着启动类也是一个IOC容器的配置类。
- 任何一个加了@Configuration注解的类都是一个IOC容器配置类,在这个配置类中任何添加了@Bean注解的方法的返回值都会定义一个bean注册到spring容器管理,方法名默认是这个bean的id。相当于xml中的<bean id=“xxx” class=“xxx.xxx.xxx”/>
@ComponentScan
- ComponentScan注解的主要作用是扫描指定路径下标识了需要装配的类(默认扫描当前类路径),自动装配到Spring IOC容器管理。
- 标识需要装配的类主要形式是:@Component、@Repository、@Service、@Controller以及派生自@Component注解的注解。
- 相当于xml中的<context:component-scan/>。
@EnableAutoConfiguration
- 自动装配类到Spring IOC容器管理
- 在spring3.1版本中,提供了一系列@Enable开头的注解,该系列注解实在javaconfig上的进一步完善,避免使用大量配置从而降低功能代码的使用难度。
- 比如常见的@EnableWebMvc引入springmvc框架需要使用到的bean。
- 比如常见的@EnableScheduling,开启任务调度的支持。
- 经查看代码发现每个@Enable开头的注解都包含了@Import注解。
@Import
- 用于把多个javaconfig的容器配置类(@Configuration)整合到一个配置中。
- 相当于xml中的<import resource/>
- @Import类注解可以配置三种不同的class:
- 将普通的bean和@Configuration的配置的bean进行注入。
- 实现ImportSelect接口进行动态注入。
- 实现ImportBeanDefinitionRegistrar接口进行注入。
三、深入分析@EnableAutoConfiguration
EnableAutoConfiguration注解的主要作用是帮助springboot应用把所有符合@Configuration配置类都加载Spring IOC容器中。
根据 AutoConfigurationImportSelector 动态注入类自动装配到Spring IOC容器中。
根据@Import引入的AutoConfigurationImportSelector类进行下一步了解
AutoConfigurationImportSelector
根据@Import装配类的特性,并且 AutoConfigurationImportSelector 实现自 ImportSelector 类,所以知道它可以根据 AutoConfigurationImportSelector 的实现在
selectImports
方法返回的数组(类的全类名)去自动装配bean到Spring IOC容器中。
根据查看 AutoConfigurationImportSelector 类代码发现 ,EnableAutoConfiguration 会帮助springboot 应用把所有符合@Configuration 配置都加载到当前 SpringBoot 创建的Spring IOC 容器中,而这里面借助了Spring 框架提供的一个工具类 SpringFactoriesLoader 的支持。以及用到了 Spring 提供的条件注解@Conditional,选择性的针对需要加载的 bean 进行条件过滤。
SpringFactoriesLoader
SpringFactoriesLoader会读取所有的spring.factories文件,不过这个工具类的原理和java和dubbo中的SPI机制一样,不过它比SPI更好的点在于不会一次性加载所有类,而是根据key进行加载,key是以Enable开头的启用类注解的名字,这里使用的是@EnableAutoConfiguration所以key是EnableAutoConfiuration的全类名。
这是随便搜索的一个spring.factories文件,每一个实现了starter的jar包都可能存在这个文件,这个文件存在于当前项目 META-INF/spring.factories
条件过滤
在分析 AutoConfigurationImportSelector 类源码的
selectImports
方法时,可以发现先会扫描 spring-autoconfiguration-metadata.properties文件获取元数据信息,最后在扫描spring.factories对应的类,并结合前面扫描到的元数据进行过滤,因为很多@Configuration是依托于其他框架来装配bean,当有些第三方框架不存在,则他们的class文件也不存在,没有相关依赖所以就没有必要加载这些配置类,从而减少@Configuration类的加载减少springboot项目的启动时间。
元数据文件中根据不同的条件去加载对应的配置类,也在java代码中有对应注解可以使用。
元数据代码 | java注解 | 含义 |
---|---|---|
ConditionalOnBean | @ConditionalOnBean | 在存在某个 bean 的时候 |
ConditionalOnMissingBean | @ConditionalOnMissingBean | 不存在某个 bean 的时候 |
ConditionalOnClass | @ConditionalOnClass | 当前 classpath 可以找到某个类型的类时 |
ConditionalOnMissingClass | @ConditionalOnMissingClass | 当前 classpath 不可以找到某个类型的类时 |
ConditionalOnResource | @ConditionalOnResource | 当前 classpath 是否存在某个资源文件 |
ConditionalOnProperty | @ConditionalOnProperty | 当前 jvm 是否包含某个系统属性为某个值ConditionalOnBean |
ConditionalOnWebApplication | @ConditionalOnWebApplication | 当前 spring context 是否是 web 应用程序 |
四、starter
starter是spring boot项目的开箱即用机制,使得我们在开发业务时能方便的使用各种第三方中间件,也可以使用自己实现的starter依赖包,从而不需要过多的框架依赖的配置。
starer是spring boot中一个很重要的概念,starter相当于一个模块,它能将所需要的的依赖整合在一起并对模块内的bean自动装配到spring IOC容器,使用者只需要在maven中依赖相应的starter包并无需做过多的依赖即可进行开发。
starer就是结合自动装配和装配配置的实现,自己可创建项目结合spring boot注解加spring.factories和外部化配置实现自己的starer包。
外部化配置
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>版本号</version>
<optional>true</optional>
</dependency>
在配置实体类上添加注解
@ConfigurationProperties(prefix="xxx.xxx.xxx")
在启动类添加@EnableConfigurationProperties(xxx.class)注解
starer项目使用这个配置值的地方直接注入添加了@ConfigurationProperties的bean进行获取
外部项目即可直接在application.properties使用