我正在创建一个spring.config.import工厂,但看不到如何从调用(父(文档访问属性
# mish-mash of properties without a common prefix
key1 = value1
key2 = value2
# now I want to read key1, key2 inside the factory
spring.config.import = myfactory:
在我的实现内部
@Configuration
public class MyFactoryResolver implements ConfigDataLocationResolver<MyResource>, Ordered {
@Override
public List<MyResource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
// how do I get the values or key1 and key2
// tried
binder.bind("key1", String.class).get(); // FAIL
// key1 needs to be in a higher source like environment KEY1=VALUE1
}
// tried as field
@Value("${key1}")
String key1; // always null
// cannot inject; too early in life-cycle ?
}
现在spring云客户端可以做这个
spring.cloud.config.username = johndoe
spring.cloud.config.password = john's password
spring.config.import = configserver:http://myserver.com
--很明显,可以从父文档中读取属性值。
但我看不出这个代码是如何工作的——这个代码对我来说是巴洛克式的/神秘的:
- 它不会简单地读取类似
spring.cloud.config.username
的属性 - 相反,它创建了一个sidekick
@ConfigurationProperties ClientConfigProperties
bean(如何?(,该bean封装所有spring.cloud.config.*
键/值。这个bean不能被注入(在生命周期的早期??(,所以它是从Binder
中检索的,然后所有属性都可用;所以如果这些属性可以从一个伙伴那里读,为什么我不能我很容易地读 - 我的属性没有标准前缀,所以创建
@ConfigurationProperties
侧踢并不容易 - 。。。在spring-cloud-config客户端的代码中,你有时会看到
new ClientConfigProperties(...)
——我一直认为这在DI领域是被禁止的,因为容器无法为你管理它
TL;DR-我正在寻找的是一种从调用工厂的文档或姐妹文档的上下文(binder?(中读取属性/键值的方法;而不必创建一个side-kick bean并强制所有属性确认前缀命名。(这是一个未强制执行属性名称的遗留应用程序…(。
更新:我试图将sidekick模式——标准化的属性名称复制到一个前缀和一个段,创建了一个holder@ConfiguationProperties
bean,并将其添加为EnableAutoConfiguration
工厂(从spring-cloud-config中复制pasta(。复制代码:
private MyProperties resolveHook(ConfigDataLocationResolverContext context) {
// TODO Auto-generated method stub
boolean registered = context.getBootstrapContext().isRegistered(MyProperties.class);
System.out.println("RESOLVER: MyProperties is registered = " + registered);
if (registered) {
return context.getBootstrapContext().get(MyProperties.class);
}
Binder localBinder = context.getBinder();
BindHandler localHandler = context.getBootstrapContext().getOrElse(BindHandler.class, null);
System.out.println("RESOLVER: BindHandler is null? " + (localHandler == null));
BindResult<MyProperties> object = localBinder.bind(MyProperties.PREFIX,
Bindable.of(MyProperties.class), localHandler);
System.out.println("RESOLVER: object is bound? " + (object.isBound()));
if (object.isBound()) {
MyProperties properties = object.get();
context.getBootstrapContext().registerIfAbsent(MyProperties.class, InstanceSupplier.of(properties));
System.out.println(
"RESOLVER: register object of type " + (properties.getClass().getName()) + " " + properties);
return properties;
}
return null;
}
神圣的奶牛——这确实有效——创建了sidekickbean,所有字段都从父文档注入。然后解析器可以读取属性值——然而,这肯定是最模糊和最全面的做事方式,而且必须有一个更简单的方法?
当我把这个问题作为问题发布到Spring存储库时,答案归功于Spring团队(GH的philweb(https://github.com/spring-projects/spring-boot/issues/32854:
在实现ConfigDataLocationResolver
时,我错误地使用了可以作为构造函数注入的绑定器。相反,应该使用overriden方法的第一个参数中的绑定器:
// Constructor
public MyResolver(Log log, Binder binder) {
super();
this.log = log;
// don't use this object to access properties
// from the invoking properties file
this.binder = binder;
}
@Override
boolean isResolvable(ConfigDataLocationResolverContext context...) {
Binder localBinder = context.getBinder();
// this object has access to properties defined in the invoking
// parent application.properties
}
TL;DR有许多绑定对象可以访问(构造函数注入,从上下文(——应该使用上下文中的Binder
,而不是构造函数。