5

プロパティ ファイルがあり、Spring プロパティ プレース ホルダーを使用して、Spring Bean に値を設定します。現在、このプロパティ ファイルは実行時に変更される可能性があります。この新しく変更されたプロパティ値で Spring Bean のプロパティを更新する方法はありますか? 特に、私は多くのシングルトン Bean を持っていますか? 新しい値でそれらを更新するにはどうすればよいですか? これに対する解決策は既にありますか、それともカスタム コードにする必要がありますか? まだ存在しない場合、誰かがこれを達成するための最良の方法を教えてください。ありがとう!

PS: 私のアプリケーションはバッチ アプリケーションです。Spring ベースの Quartz 構成を使用して、バッチをスケジュールします。

4

1 に答える 1

3

参照用にこれを残しますが、更新された回答は仕切りの下にあります:

ConfigurableApplicationContextインターフェースにはrefresh ()メソッドが含まれていますが、これは必要なはずですが、問題は、そのメソッドにアクセスする方法です。どちらの方法でも、 type の依存関係を持つ Bean から開始しますConfigurableApplicationContext

private ConfigurableApplicationContext context;
@Autowired
public void setContext(ConfigurableApplicationContext ctx){
    this.context = ctx;
}

ここで、私が提案する2つの基本的なオプションは、次のいずれかです

  1. タスク実行フレームワークを使用して、Bean にプロパティ リソースを定期的に監視させ、変更が見つかったときに ApplicationContext を更新するか、
  2. Bean を JMXに公開して、更新を手動でトリガーできるようにします。

コメントを参照してください: コンテキスト全体を更新することは不可能に思われるため、代わりの戦略は、プロパティ ファクトリ Bean を作成し、それを他のすべての Bean に注入することです。

public class PropertiesFactoryBean implements FactoryBean<Properties>{

    public void setPropertiesResource(Resource propertiesResource){
        this.propertiesResource = propertiesResource;
    }

    private Properties value=null;
    long lastChange = -1L;

    private Resource propertiesResource;

    @Override
    public Properties getObject() throws Exception{
        synchronized(this){
            long resourceModification = propertiesResource.lastModified();
            if(resourceModification != lastChange){
                Properties newProps = new Properties();
                InputStream is = propertiesResource.getInputStream();
                try{
                    newProps.load(is);
                } catch(IOException e){
                    throw e;
                } finally{
                    IOUtils.closeQuietly(is);
                }
                value=newProps;
                lastChange= resourceModification;
            }
        }
        // you might want to return a defensive copy here
        return value;
    }

    @Override
    public Class<?> getObjectType(){
        return Properties.class;
    }

    @Override
    public boolean isSingleton(){
        return false;
    }

}

このプロパティ Bean を他のすべての Bean に注入することもできますが、常にプロトタイプ スコープを使用するように注意する必要があります。これはシングルトン Bean 内では特に注意が必要です。解決策はここにあります

あちこちにルックアップ メソッドを注入したくない場合は、次のPropertyProviderように Bean を注入することもできます。

public class PropertiesProvider implements ApplicationContextAware{

    private String propertyBeanName;
    private ApplicationContext applicationContext;

    public void setPropertyBeanName(final String propertyBeanName){
        this.propertyBeanName = propertyBeanName;
    }

    @Override
    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException{
        this.applicationContext = applicationContext;
    }

    public String getProperty(final String propertyName){
        return ((Properties) applicationContext.getBean(propertyBeanName)).getProperty(propertyName);
    }

}
于 2010-11-03T08:05:22.277 に答える