Java 提高spring库对可扩展配置对象的明确性
我目前正在开发一个spring库,它允许用户定义的配置类(与@Configuration无关)在使用之前从应用程序的另一部分进行调整:Java 提高spring库对可扩展配置对象的明确性,java,spring,design-patterns,configuration,Java,Spring,Design Patterns,Configuration,我目前正在开发一个spring库,它允许用户定义的配置类(与@Configuration无关)在使用之前从应用程序的另一部分进行调整: interface ConfigAdjuster<T extends Config<T>> { void adjust(T t); } abstract class Config<T extends Config<T>> { @Autowired Optional<ConfigA
interface ConfigAdjuster<T extends Config<T>> {
void adjust(T t);
}
abstract class Config<T extends Config<T>> {
@Autowired
Optional<ConfigAdjuster<T>> adjuster;
@PostConstruct
private void init() {
//i know this cast is somewhat unsafe, just ignore it for this question
adjuster.ifPresent(a -> a.adjust((T)this));
}
}
接口配置调整器{
空隙调整(T);
}
抽象类配置{
@自动连线
可选调节器;
@施工后
私有void init(){
//我知道这个演员阵容有点不安全,只是在这个问题上忽略它
调整器。如果存在(a->a.调整((T)此));
}
}
这可以按如下方式使用:
class MyConfig extends Config<MyConfig> {
//imagine many fields of more complex types
public String myData;
}
@Configuration
class MyConfigDefaults {
@Profile("dev")
@Bean
public MyConfig devDefaults() {
//imagine setting defaults values here
return new MyConfig();
}
}
类MyConfig扩展配置{
//想象许多更复杂类型的字段
公共字符串myData;
}
@配置
类MyConfigDefaults{
@简介(“开发”)
@豆子
公共MyConfig devDefaults(){
//想象一下在这里设置默认值
返回新的MyConfig();
}
}
现在,使用MyConfig的库的使用者可以在其应用程序中执行以下操作:
@Bean
public ConfigAdjuster<MyConfig> adjustDefaults() {
return cfg -> {
cfg.myData = "something_other_than_default";
}
}
@Bean
公共配置默认值(){
返回cfg->{
cfg.myData=“除默认值之外的其他内容”;
}
}
我看到这种方法的最大问题是整个“调整配置”部分对用户来说有些隐藏。通过使用ConfigRegulator,您很难判断是否可以更改默认配置。在最坏的情况下,用户会尝试自动连接配置对象,并尝试对其进行修改,从而导致未定义的行为,因为其他组件可能已经用默认值初始化
有没有一种简单的方法可以让这种方法比现在更“有说服力”?整个想法是不要在多个项目中复制和粘贴整个默认配置+调整部分
使所有这些更显式的一种方法是在Config的构造函数中要求调整器,但这会污染每个构造函数和内置类的使用
有什么想法吗
编辑:请注意,这是该库的简化版本,我确实知道私有@PostConstruct等的含义。如果您有其他方法在没有@PostConstruct的情况下实现所有这些,请分享:)
编辑2:
让我再次概述这个图书馆的主要目标:
您的问题有两种解决方案: 1-定义一个通用的定制器,例如:
public interface Customizer<T> {
T customize(T t);
boolean supports(Class target);
}
public interface MyConfigCustomizer{
MyConfig customize(MyConfig config);
}
因此,您的默认配置应该如下所示:
@Configuration
public class DefaultConfiguration {
@Autowired(required = false)
private List<Customizer> customizers;
@Bean
public MyConfig myConfig() {
MyConfig myConfig = new MyConfig();
myConfig.setProperty("default value");
if (customizers != null) {
for (Customizer c : customizers) {
if (c.supports(MyConfig.class)) {
return (MyConfig) c.customize(myConfig);
}
}
}
return myConfig;
}
}
您的默认配置:
@Configuration
public class DefaultConfiguration {
@Autowired(required = false)
private MyConfigCustomizer customizer;
@Bean
public MyConfig myConfig() {
MyConfig myConfig = new MyConfig();
myConfig.setProperty("default value");
if (customizer != null) {
return customizer.customize(myconfig);
}
return myConfig;
}
}
通过这种方式,用户知道MyConfig可以调整(而不是所有的bean)。有两种解决方案: 1-定义一个通用的定制器,例如:
public interface Customizer<T> {
T customize(T t);
boolean supports(Class target);
}
public interface MyConfigCustomizer{
MyConfig customize(MyConfig config);
}
因此,您的默认配置应该如下所示:
@Configuration
public class DefaultConfiguration {
@Autowired(required = false)
private List<Customizer> customizers;
@Bean
public MyConfig myConfig() {
MyConfig myConfig = new MyConfig();
myConfig.setProperty("default value");
if (customizers != null) {
for (Customizer c : customizers) {
if (c.supports(MyConfig.class)) {
return (MyConfig) c.customize(myConfig);
}
}
}
return myConfig;
}
}
您的默认配置:
@Configuration
public class DefaultConfiguration {
@Autowired(required = false)
private MyConfigCustomizer customizer;
@Bean
public MyConfig myConfig() {
MyConfig myConfig = new MyConfig();
myConfig.setProperty("default value");
if (customizer != null) {
return customizer.customize(myconfig);
}
return myConfig;
}
}
通过这种方式,用户知道MyConfig是可以调整的(而不是所有的bean)。与此相关的内容可以帮助您:
@Primary
和类似的@ConditionalOnMissingBean
完全没有帮助,因为它们不允许用户自定义默认配置对象的某些部分,只有所有这些都消除了默认配置对象的大部分好处,这才有助于您:@Primary
和类似的@ConditionalOnMissingBean
根本没有帮助,因为它们不允许用户自定义默认配置对象的某些部分,只有所有这些都消除了默认配置对象的大部分好处。第二个变体不是和我发布的完全一样吗?唯一不同的是,库用户在定义其默认配置时必须自己自动连接自定义程序,对吗?这种方法的主要问题是,作为库用户,您可能会忘记自动连接自定义程序并应用它-我希望库能够处理这个问题。谢谢你的意见@naze我认为您不了解这种方法,在您的库中,您需要定义配置(库中所有必需的bean(包括默认初始化))并让用户创建自定义程序(如果他需要),这样做时,自定义程序将自动连接到库中,用户需要做的唯一一件事就是在代码中的某个地方将他的定制器声明为Bean。似乎对我的问题的描述是错误的——这正是我的方法的工作原理。我认为误解在于双重用法:库创建者使用我的库->其他人使用所述库->用户只需创建自定义项。第二个变体不是与我发布的完全相同吗?唯一不同的是,库用户在定义其默认配置时必须自己自动连接自定义程序,对吗?这种方法的主要问题是,作为库用户,您可能会忘记自动连接自定义程序并应用它-我希望库能够处理这个问题。谢谢你的意见@naze我认为您不了解这种方法,在您的库中,您需要定义配置(库中所有必需的bean(包括默认初始化))并让用户创建自定义程序(如果他需要),这样做时,自定义程序将自动连接到库中,用户需要做的唯一一件事就是在代码中的某个地方将他的定制器声明为Bean。似乎对我的问题的描述是错误的——这正是我的方法的工作原理。我认为误解在于双重使用:库创建者使用我的库->其他人使用所述库->用户只需创建定制器