1C.自动配置机制
1C.自动配置机制
利用SpringBoot的特性,完成自动配置。
1C.1.自动规则和命名
有特殊功能的spring命名,主要集中在以下(后续目录结构有详解)
/wings-conf/自动加载,分割的配置文件/wings-i18n/自动加载,分割的多国语的信息文件**/spring/boot/手动加载,Boot有关的配置,如spring.factories**/spring/bean/自动加载,比如@ComponentScan指定**/spring/conf/Configurer或AutoConfiguration**/spring/prop/properties的映射**/spring/help/配置助手*Configuration.java条件加载,配置项以wings.enabled.为前缀
使用idea开发时,会有黄色警告或提示,不影响运行,但看着碍眼
- 提示Application context not configured for this file, 在
Project Structure/Facets/Spring手动添加boot/WingsAutoConfiguration一个即可。 - 提示 annotation processing的设置,在
Settings/Annotation Processors/Enable annotation processing - 注意:在
@Configuration中的内部类,static class是按独立类处理的,不受外层约束。
在wings工程中,会存在wings-enabled.properties配置,作为功能开关。 可以设置wings.enabled.silencer.verbose=true 通过日志的INFO查看。
1C.2.属性bind和meta提示
属性类统一用*Prop.java和@Data,经过配置后,可以自动提示。
- 手动添加 additional-spring-configuration-metadata.json
- 自动生成 spring-configuration-metadata.json
参考资料
- https://docs.spring.io/spring-boot/docs/3.0.3/reference/htmlsingle/#appendix.configuration-metadata
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding
- https://github.com/spring-projects/spring-boot/wiki/IDE-binding-features#simple-pojo
1C.3.按条件配置事项
- 配置类为
*Configuration.java在/spring/bean/中 - 属性类为
*Prop.java在/spring/prop/中 - 嵌套配置不继承
@Conditional- 要合并为
@ConditionalOnExpression - 或自定义一个
@Conditional
- 要合并为
- 多个
@Conditional为and逻辑 - 多个
Condition为and逻辑
以下为Conditional javadoc
The
@Conditionalannotation may be used in any of the following ways:
- as a type-level annotation on any class directly or indirectly annotated with
@Component, including@Configurationclasses- as a meta-annotation, for the purpose of composing custom stereotype annotations
- as a method-level annotation on any
@BeanmethodIf a
@Configurationclass is marked with@Conditional,all of the@Beanmethods,@Importannotations, and@ComponentScanannotations associated with that class will be subject to the conditions.NOTE: Inheritance of
@Conditionalannotations is not supported; any conditions from superclasses or from overridden methods will not be considered.
1C.4.ConditionalOnClass无效
如下代码,ConditionalOnClass置于同类型的Bean声明上,会报错 NoClassDefFoundError
@Bean
@ConditionalOnClass(SomeService.class)
public SomeService someService() {
return new SomeService();
}需要改为如下这种,内类控制的Configuration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SomeService.class)
public static class SomeServiceConfiguration {
@Bean
public SomeService someService() {
return new SomeService();
}
}参考Creating Your Own Auto-configuration
1C.5.禁用任意 @Component
在spring的@Conditional自动配置体系中,On*Bean 依赖于Bean的注册顺序,很难发现问题。 所以在wings中,把问题提前到启动阶段,尽早发现Bean冲突,可通过设置属性文件关闭不需要功能。
在@Configuration, @Bean和任何@Component上,使用以下@ConditionalWingsEnabled 并指定限定key,可以禁用任意Component和Bean,
限定key = 前缀. + 全类名 + .方法名? = true|false
- 前缀 - 默认 wings.enabled
- 全类名 - 比如 pro.fessional.wings.silencer.spring.boot.WingsEnabledCondition
- 方法名 - 比如 crc8Long
@*Configuration 的命名规则如下,
*AutoConfiguration-@AutoConfiguration@Import@Configuration*Configuration- 顶级@Configuration及其@Bean*Event- 内类@Configuration及其@EventListener*Wired- 内类@Configuration及其@Autowired*Bean- 内类@Configuration及其包装的单一@Bean **Scan- 内类@Configuration用来@ComponentScan
@ConditionalWingsEnabled 具有以下增强功能
- abs -
绝对key,无视前缀,优先级低于限定key - key -
相对key,使用前缀,优先级低于绝对key - value - 默认值,最低优先级,key不存在时使用
- and, not -
this && and1 && and2 && !not1 && !not2
其中,限定key相当于id,全局唯一,具有最高优先级,绝对key和相对key相当于别名, 不需要唯一,可以多处共用。这三种key的优先级从高到低如下,
- 限定key =
prefix+ClassName+methodName? - 绝对key =
abs() - 相对key =
prefix+key() - 默认值 =
value()
除了注解的精确控制,也可以通过以下属性,对限定key实现ant-matcher规则的控制。
- wings.feature.error
- wings.feature.prefix
- wings.feature.enable
## ... 为包名缩写
## @ConditionalWingsEnabled(prefix = "catty.enabled")
## 禁用 @Bean catBean 于 WingsEnabledCatConfiguration
catty.enabled.pro...WingsEnabledCatConfiguration.catBean=false
## 禁用 InnerCatConfiguration 及其 Bean
catty.enabled.pro...WingsEnabledCatConfiguration$InnerCatConfiguration=false
## @Conditional(WingsEnabledCondition.class) or @ConditionalWingsEnabled
## 禁用 @Bean dogBean 于 WingsEnabledDogConfiguration
wings.enabled.pro...WingsEnabledDogConfiguration.dogBean=false
## 禁用 InnerDogConfiguration 及其 Bean
wings.enabled.pro...WingsEnabledDogConfiguration$InnerDogConfiguration=false1C.6.功能开关 FeatureFlags
Wings的FeatureFlags实现,有以下两个层面,
- 配置级 -
@ConditionalWingsEnabled作用在@Component和@Bean - 线程级 -
FeatureFlag作用在逻辑
此两种方式的原理相同,基于wings.feature和wings.enabled配置。
在业务编码中,使用以下工具类,可实现切换业务逻辑,
FeatureFlag- 以Class为key获取功能状态TweakFeature- 全局或线程级动态开关功能
功能开关的优先级如下,
@ConditionalWingsEnabled- Conf类 或 Bean方法- qualified-key =
prefix.+ClassName+.methodName? - absolute-key =
abs() - relative-key =
prefix.+key() - default =
value(),仅当无配置项时 and(), 然后not()- 仅当本功能开启时
- qualified-key =
wings.enabled.*- 字符串格式配置项,一对一wings.feature.*- ant风格配置项,一对多,仅当无一对一时FeatureFlag-TweakFeature,然后WingsEnabledContext
1C.7.配置Bean的Order
使用wings.reorder.*属性,其中*为,
beanName- 按名字一对一调整,高优先级beanClass- 按类型一对多调整
其影响范围包括,
List<Bean>- 注入的有序的集合类.orderedStream()- ObjectProvider的排序
和顺序有关的优先级如下,注意Bean的声明和扫描机制不同,影响优先级,
wings.reorder.*配置,最高优先级- 当
@Bean时,@Order高于Ordered - 当
@Component时,Ordered高于@Order
以下任一情况,此功能无效,
- 配置项为空或配置的Bean不存在
- wings.enabled.silencer.bean-reorder=false
也可以通过wings.primary.*设置Bean的Primary,但仅支持beanName。
// wings.reorder.getterClass2 = 3
@Bean
public GetterClass getterClass2()
// wings.primary.testReorderServiceImpl2=true
// wings.reorder.testReorderServiceImpl2 = 3 # or
// wings.reorder.pro.fessional.wings.silencer.app.service.impl.TestReorderServiceImpl2=3
@Service
public class TestReorderServiceImpl2