SpringBoot Reference 2.7.11

发布时间 2023-12-22 21:47:24作者: Bingmous

Using Spring Boot

Build Systems

  • 依赖管理:建议使用maven 或gradle做依赖管理
  • starters

代码风格

  • 主启动类使用 @SpringBootApplication 或 @EnableAutoConfiguration + @ComponentScan

配置类

  • 建议主启动类是一个单一的配置类
  • 导入其他配置类使用:@Configuration,@Import,或者使用@ComponentScan指定扫描包
  • 导入xml配置文件使用:@ImportResource

自动配置

  • 使用@EnableAutoConfiguration or @SpringBootApplication在任意一个@Configuration上面(其他@Component也可以吧),建议只放在主配置类上面
  • 自动配置是非侵入性的,如果自己配置了相关的bean,自动配置的bean就不会生效了。可以添加启动参数--debug,在日志中可以查看哪些自动配置生效了,或者配置文件debug=true
  • 关掉自动配置类:@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }),该属性是@EnableAutoConfiguration的别名。也可以使用配置文件:spring.autoconfigure.exclude
    • 自动配置类虽然是public的,但作为public api的唯一目的就是类的名称也可以在外部拿到用于关掉自动配置,内部配置类或方法是内部使用的不建议直接使用

Spring Beans and Dependency Injection

  • 虽然可以使用任意标准的Spring框架定义bean以及依赖注入,但是推荐使用构造器注入,使用@ComponentScan查找bean
    • 如果有多个构造器,需要指定一个@Autowired让Spring使用
    • 使用构造器注入可以让字段标记为final,表示其后续不可用被更改

spring注入,默认名称为类名称,首字母小写;@Bean创建默认
是方法名称

使用@SpringBootApplication注解

  • 使用这个注解可以开启三个功能:
    • @EnableAutoConfiguration,开启自动配置机制
    • @ComponentScan,开启注解扫描,扫描主启动所在的包
    • @SpringBootConfiguration,开启注入上下文中其他的bean或者import其他的配置类
  • @SpringBootApplication注解中也提供了@EnableAutoConfiguration@ComponentScan定制属性的别名

Running Your Application

  • ide运行
  • java -jar运行,java -Xdebug运行
  • 插件运行:mvn spring-boot:run
  • 热加载:使用spring-boot-devtools快速重启应用

开发者工具

  • 使用依赖spring-boot-devtools,多模块下可能导致类加载问题。
    • 打包时该功能是关闭的,如果使用特殊的类加载器并将该功能作为生产级别应用使用-Dspring.devtools.restart.enabled=true开启,不建议在生产环境中使用。
    • 将该依赖作为optional防止被其他应用使用。repackaged默认不会打包devtools,如果需要使用,可以使用mavne插件的时候设置excludeDevtools为false
  • 默认属性:spring-boot-devtools默认是关闭缓存的,缓存可以通过配置文件配置,spring-boot-devtools会自动应用配置文件配置,比如spring.thymeleaf.cache。如果不使用配置文件的配置,设置spring.devtools.add-properties=false
  • 因为在开发SpringMVC和Spring Webflux时可能需要更多的信息,所以建议开启debug日志,这样就可以看到请求信息、handler信息等等细节。如果你希望查看所有请求细节,可以开启spring.mvc.log-request-details or spring.codec.log-request-details
  • 自动重启:
    • 使用maven的build插件必须forking设置为enabled,否则devtools的应用类加载器不会被创建,重启操作也不会执行
    • devtools依赖于应用上下文的shutdown hook,如果设置了SpringApplication.setRegisterShutdownHook(false),重启也不会工作
    • 使用aspectj weaving是重启不支持
    • springboot提供的重启技术是用了两个类加载器,一个加载第三方jar,一个加载正在开发的jar,应用重启时只重启正在开发的哪个加载器,会快一点
    • 打印条件报告:默认每次重启的时候会在日志中打印哪些bean、配置文件变更,如果不打印设置`spring.devtools.restart.log-condition-evaluation-delta=false
    • 排查触发重启的资源变更:默认 /META-INF/maven, /META-INF/resources, /resources, /static, /public, or /templates不会触发重启,但会触发热更新liveLoad,修改默认排查的资源spring.devtools.restart.exclude=static/**,public/**,添加额外排查的资源使用spring.devtools.restart.additional-exclude
    • 增加其他的资源变更监控:spring.devtools.restart.additional-paths
    • 关闭重启策略:spring.devtools.restart.enabled=false,在配置文件中修改依然初始化restart类加载器,但是不监控任何资源变更。如果要完全关闭,在run之前设置系统属性System.setProperty("spring.devtools.restart.enabled", "false");
    • 使用触发文件:spring.devtools.restart.trigger-file=.reloadtrigger,只有当该文件改动时,才触发重启

Core Feature

Creating Your Own Auto-configuration

自动配置一般与一个starter关联,提供自动配置代码以及一些要使用的lib

理解自动配置:

  • 自动配置类使用注解@AutoConfiguration,这个注解是一个配置的元注解(@Configuration),使得自动配置类是一个标准的配置类
  • 其他的@Conditional用于限制什么时候这个配置会生效
    • @ConditionalOnClass
    • @ConditionalOnMissingBean,保证在有这些类但是没有声明自己的@Configuration时自动配置才生效
    • 可以参考spring-boot-autoconfigure源码的@AutoConfiguration,以及文件METAINF/ spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

加载自动配置候选项

jar包中METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,指定需要加载的配置类,要确保自动配置类在一个具体的包下,不应作为组件扫描,可以使用@Imports代替

如果自动配置需要以一定的顺序执行,可以使用@AutoConfiguration的before, beforeName,after and afterName attributes,或者@AutoConfigureBefore and @AutoConfigureAfter annotations.。也可以使用@AutoConfigureOrder指定顺序,它与@Order有相同的语义,只是作用于自动配置类。

和标准的@Configuration一样,自动配置类的顺序只影响里面的bean的定义的顺序,不会影响这些bean的创建的顺序,创建顺序只取决于bean之间的依赖关系和@DependsOn指定的关系。

条件注解

@ConditionalOnMissingBean可以用来覆盖默认的自动配置类,如果不想要默认的自动配置类。

sping有一系列条件注解,这些注解可以在@Configuration类或@Bean方法上使用

• Class Conditions
• Bean Conditions
• Property Conditions
• Resource Conditions
• Web Application Conditions
• SpEL Expression Conditions

class条件注解(放在配置类、或自动配置类或@Bean方法上)

  • @ConditionalOnClass@ConditionalOnMissingClass可以让配置类基于某些具体的类存在或不存在进行生效,由于注解元数据是用ASM解析的,所以可以使用value属性指向实际的类,即使类可能实际不存在。
  • 也可以使用string类型的name属性指定具体的类名称。不过这个不适用于@Bean,因为@Bean方法的返回值会用来判断条件的,方法上的条件生效前,jvm会加载@Bean相关的类并且处理相关的方法引用,如果类不存在会导致失败。为了处理这个创建,可以单独使用一个@Configuration类来隔离条件(@Configuration类的内部类里加载这些@Bean

注意:如果使用类的条件注解开发自己的注解,比如使用name,因为指定class这种情况没有处理。

bean条件注解(放在配置类、或自动配置类或@Bean方法上)

  • @ConditionalOnBean@ConditionalOnMissingBean,可以使用value指定类型或name指定bean的名称
  • search属性可以用于在查找bean时限制ApplicationContext的层次结构
  • 使用@Bean在一个方法上时,方法的返回值的类型是bean的目标类型
  • 注意@Bean的使用顺序,是按照定义的添加顺序进行解析的,所以推荐使用@ConditionalOnBean@ConditionalOnMissingBean在自动配置类上,因为这样肯定会在用户定义的bean之后加载。
  • @ConditionalOnBean and @ConditionalOnMissingBean放在@Configuration配置类上会决定该配置类是否会创建(如果不创建里面的方法也不会执行),放在@Bean方法上决定该方法是否会执行
  • @Bean返回的类型应该尽可能的具体,以提供更多的信息给bean条件注解使用

property条件注解(放在配置类、或自动配置类或@Bean方法上)

  • @ConditionalOnPropertyvaluename指定配置的key,prefix指定配置的前缀,二者组合起来为key的全名,由两个逻辑:matchIfMissing控制没配置时是否算匹配,havingValue控制如果匹配了值是否匹配(不区分大小写)
  • matchIfMissing,(考虑配置不存在时的逻辑是什么,由用户确定)
    • 默认为false,即如果没有这个配置就不满足条件
    • 如果配置了true,即使没有指定属性也算你配置了(那直接不加这个注解不就行了?不行,因为可以存在时继续判断配置的value是否满足,即要么不配,要么配某个指定的value)
  • 注意当没有显示指定havingValue的值,则配置中的该property不能是false,否则该条件为不满足。
    • 底层逻辑是:如果没有指定havingValue的值即"", 则实际值跟false比较,如果匹配说明条件满足
    		private boolean isMatch(String value, String requiredValue) {//requiredValue为注解中配置的值
    		if (StringUtils.hasLength(requiredValue)) {
    			return requiredValue.equalsIgnoreCase(value);
    		}
    		return !"false".equalsIgnoreCase(value);
    	}
    

resource条件注解(放在配置类、或自动配置类或@Bean方法上)

  • @ConditionalOnResource

web application条件注解

  • @ConditionalOnWebApplication@ConditionalOnNotWebApplication,只要使用WebApplicationContextConfigurableWebEnvironmentReactiveWebApplicationContextConfigurableReactiveWebEnvironment

SpEL表达式添加注解
@ConditionalOnExpression

  • 注意:spel表达式中引用bean会导致bean非常早的进行初始化,还没有来得及进行后置处理(如配置绑定),因此它的状态可能不完整。

说明

  • 如果是引入starter就生效,应该使用@AutoConfiguration类+开启自动配置的方式(@EnableAutoConfiguration+扫描包、@ImportAutoConfiguration指定某些自动配置(既然是自动配置了,应该不需要用户Import了吧)))
  • 如果是有某些配置就bean就生效,应该直接使用@Configuration,不用开启自动配置也可以控制逻辑

测试自动配置类

  • 使用ApplicationContextRunner
  • 如果自动配置是在servlet或web下才进行的,可以使用WebApplicationContextRunner or ReactiveWebApplicationContextRunner来仿真web环境
  • 覆盖类路径

创建自己的starter

  • 一般starter会有两个module,一个是autoConfigure用于包含自动配置代码,一个是starter只包含所需的所有依赖
    • 这并不是必要的,如果没有可选的特性
    • 如果starter有可选项、可选特性,则最好是将自动配置单独分开,能清楚的表达一些特性是可选的,同时别人也可以基于autoConfigure开发自己的starter

命名:模块不要以spring-boot开头,starter使用xxx-spring-boot-starter

配置key:使用唯一的命名空间,不要包含spring的,每个配置属性要有javadoc。要触发产生配置的元数据META-INF/spring-configuration-metadata.json

自动配置模块:包含所有必要东西,包括库。使用spring-boot-autoconfigure-processor收集自动配置的条件,可以用来过滤自动配置,减少启动时间。注意这个依赖在plugin中要排除掉,避免repackage把依赖添加到fatjar中

starter模块:是一个空的jar,它的目的就是提供必要的依赖让他们一起工作,