在spring.config.import工厂中,如何访问调用文档中的属性?

r3i60tvu  于 2022-11-21  发布在  Spring
关注(0)|答案(1)|浏览(116)

我正在创建一个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-cloud-client可以做到这一点

spring.cloud.config.username = johndoe
spring.cloud.config.password = john's password
spring.config.import = configserver:http://myserver.com
  • 因此很明显可以从父文档中读取属性值。
    但我看不出这段代码是如何工作的--这段代码对我来说是巴洛克式的/神秘的:
  • 它不会简单地读取spring.cloud.config.username这样的属性
  • 相反,它创建了一个 Package 所有spring.cloud.config.*键/值的sidekick @ConfigurationProperties ClientConfigProperties bean(如何实现的?)。这个bean不能被注入(在生命周期的早期??),所以它是从一个Binder中检索的,然后所有的属性都可用;所以如果这些属性可以从一个助手读取,为什么我不能我很容易地读取它们...
  • 我的属性没有标准前缀,因此创建@ConfigurationProperties助手不容易
  • ...在spring-cloud-config-client的代码中,您有时会看到new ClientConfigProperties(...)-我一直认为这在DI中是禁止的,因为容器无法为您管理它。

TL;DR -我正在寻找的是一种从调用工厂的文档或姐妹文档的上下文(绑定器?)读取属性/键值的方法;而不必创建一个side-kick bean并强制所有属性确认前缀命名。(这是一个遗留应用程序,其中属性名称没有强制...)。
更新:我尝试复制sidekick模式-标准化属性名称到一个前缀和一个段,创建了一个保持器@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,所有的字段都从父文档中注入。然后解析器可以读取属性值--然而,这肯定是最模糊和迂回的方法,而且一定有更简单的方法吗?

9o685dep

9o685dep1#

当我把这个问题作为一个问题发布到Spring仓库https://github.com/spring-projects/spring-boot/issues/32854时,这个答案要归功于Spring团队(GH的philwebb):
在实现ConfigDataLocationResolver时,我错误地使用了可以注入构造函数的绑定器。相反,应该使用覆盖方法的第一个参数中的绑定器:

// 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,而不是构造函数。

相关问题