6

Zookeeper ノードから値を読み取る Spring 3.1 PropertySource を構築しようとしています。Zookeeper への接続には、Netflix のCuratorを使用しています。

そのために、Zookeeper からプロパティの値を読み取り、それを返すカスタム プロパティ ソースを作成しました。このようにプロパティを解決している場合、これは正常に機能します

ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
ctx.getEnvironment().getPropertySources().addLast(zkPropertySource);
ctx.getEnvironment().getProperty("foo"); // returns 'from zookeeper'

ただし、 @Value アノテーションを持つフィールドを持つ Bean をインスタンス化しようとすると、これは失敗します。

@Component
public class MyBean {
    @Value("${foo}") public String foo;
}

MyBean b = ctx.getBean(MyBean.class); // fails with BeanCreationException

この問題はおそらく Zookeeper とは何の関係もありませんが、プロパティ ソースを登録して Bean を作成する方法に関係しています。

どんな洞察も高く評価されます。

更新 1:

次のような XML ファイルからアプリ コンテキストを作成しています。

public class Main {
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        ctx.registerShutdownHook();
    }
}

Zookeeper に接続するクラスは @Component です。

@Component
public class Server {
    CuratorFramework zkClient;

    public void connectToZookeeper() {
        zkClient = ... (curator magic) ...
    }

    public void registerPropertySource() {
        ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
        ctx.getEnvironment().getPropertySources().addLast(zkPropertySource);
        ctx.getEnvironment().getProperty("foo"); // returns 'from zookeeper'
    }

    @PostConstruct
    public void start() {
        connectToZookeeper();
        registerPropertySource();
        MyBean b = ctx.getBean(MyBean.class);
    }
}

更新 2

これは、XML を使用しない構成、つまり @Configuration、@ComponentScan、および @PropertySource を AnnotationConfigApplicationContext と組み合わせて使用​​している場合に機能するようです。ClassPathXmlApplicationContext で機能しないのはなぜですか?

@Configuration
@ComponentScan("com.goleft")
@PropertySource({"classpath:config.properties","classpath:version.properties"})
public class AppConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}
4

1 に答える 1

5

更新 2 への回答:これは、元の構成 (を使用して PropertySource を登録する) では機能しません。これは@PostConstruct、PropertySource が非常に遅く登録されているためです。この時点までに、ターゲット Bean は既に構築および初期化されています。

通常、プレースホルダーの注入は、Spring ライフサイクルの非常に初期のBeanFactoryPostProcessorを介して行われ (この段階では Bean は作成されていません)、PropertySource がその段階で登録されている場合は、プレースホルダーを解決する必要があります。

ただし、最善の方法は、ApplicationContextInitializerを使用し、applicationContext のハンドルを取得して、そこに propertySource を登録することです。

public class CustomInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
    public void initialize(ConfigurableWebApplicationContext ctx) {
        ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
        ctx.getEnvironment().getPropertySources().addFirst(zkPropertySource);
    }
}
于 2012-08-12T22:10:11.377 に答える