本文最后更新于:2022年7月19日 下午
概览:SpringBoot自动配置
SpringBoot的优点
- 可以创建独立的Spring应用
- 内嵌web服务器,可以将jar包直接在目标服务器上执行
- 自动starter依赖,简化构建配置
- 自动配置spring以及第三方功能
- 整合了spring技术栈,也是简化spring技术栈的快速开发脚手架
Hello World
依赖
1 2 3 4 5 6 7 8 9 10 11 12
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
|
主程序
1 2 3 4 5 6 7 8 9 10
| import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class MainApplication {
public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
|
配置
starter 场景启动器
springBoot官方的starter命名规则:spring-boot-starter-*
- 只要引入了starter,这个场景下的所有常规需要的依赖都会自动引入
所有的场景启动器最底层的依赖都是spring-boot-starter
1 2 3 4 5 6
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
|
1 2 3
| <properties> <mysql.version>5.1.43</mysql.version> </properties>
|
SpringBoot自动配置特性
例如:springMVC会自动配置好web常见的问题:字符编码问题
- 默认的包结构:默认会将
MainApplication
所在包以及其下面的所有的子包组件扫描进去,无需包扫描配置
- 改变扫描:
@SpringBootApplication(scanBasePackages="com.lun")
- 各种配置都有默认值
- 默认配置都最终映射到了某个类上,xxxProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象。
- 按需加载自动配置项
- @Conditional注解
- 引入了哪个场景,哪个场景的自动配置才会开启。
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
SpringBoot重要注解
1.@SpringBootApplication
这个注解相当于三个注解
1 2 3 4 5 6 7 8 9 10
| @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )}
|
2.@Configuration与@Bean
@Configuration
这个注解的作用是告诉SpringBoot这个类是一个配置类,当然这个配置类本身也是一个组件。
- 属性:
proxyBeanMethods
:代理bean的方法
@Bean
用于方法和注解上,给容器添加组件,默认使用方法名作为组件的id,方法的返回类型就是组件类型,返回值就是组件在容器中的实例。
- 最佳实战
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
案例:mybatis-plus
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class MyBatisPlusConfig {
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); paginationInnerInterceptor.setDbType(DbType.MYSQL); paginationInnerInterceptor.setOverflow(true); interceptor.addInnerInterceptor(paginationInnerInterceptor); return interceptor; }
@Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } }
|
3.@Import导入组件
1
| @Import({User.class, DBHelper.class})
|
给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名。
4.@Conditional条件装配
满足Conditional指定的条件,则进行组件注入。
1 2 3 4 5
| @Configuration
@ConditionalOnMissingBean(name = "tom") public class MyConfig(){ }
|
5.@ImportResource引入Spring配置文件
对于一些旧的xml的bean的文件,可以使用这个注解导入。
1 2 3
| @ImportResource("classpath:beans.xml") public class MyConfig { }
|
6.@ConfigurationProperties配置绑定
对于application.properties中的配置将其封装到JavaBean中:
1 2
| mycar.brand=BYD mycar.price=100000
|
方式1:
1 2 3 4 5 6
| @Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; }
|
方式2:
1 2 3 4
| @EnableConfigurationProperties(Car.class) public class MyConfig { }
|
1 2 3 4
| @ConfigurationProperties(prefix = "mycar") public class Car { }
|
SpringBoot自动配置
核心:@SpringBootApplication
其等价于
1 2 3 4 5 6 7 8 9 10 11
| @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} )
|
@ComponentScan 定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
- 自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器
- 通过includeFilters加入扫描路径下没有以上注解的类加入spring容器
- 通过excludeFilters过滤出不用加入spring容器的类
@SpringBootConfiguration 其内部就是@Configuration
@EnableAutoConfiguration这个是核心
1 2 3 4 5 6 7 8 9 10 11 12 13
| @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 {}; }
|
@AutoConfigurationPackage – 自动配置包
1 2 3 4 5 6
| @Import({Registrar.class}) public @interface AutoConfigurationPackage { String[] basePackages() default {};
Class<?>[] basePackageClasses() default {}; }
|
- 这里可以看到使用Import导入了一个组件:Registrar.这个组件内部给容器导入了一系列组件。
- 这里的注解在MainApplication上,就是将指定包下的组件导入MainApplication所在包下?
@Import({AutoConfigurationImportSelector.class})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.getConfigurationClassFilter().filter(configurations); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
|
会从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
虽然所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration
按照条件装配规则(@Conditional
),最终会按需配置。
总结:
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
生效的配置类就会给容器中装配很多组件
只要容器中有这些组件,相当于这些功能就有了
定制化配置
用户直接自己@Bean替换底层的组件
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —-> application.properties
SpringBoot全局异常处理
@ControllerAdvice
:注解定义全局异常处理类
@ExceptionHandler
:声明异常处理方法
使用
1 2 3 4 5 6 7 8 9 10 11 12
| @ControllerAdvice @ResponseBody public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) { ...... } }
|