Spring - 使用新的Property File值替换bean属性值

SJo*_*Joe 5 java spring properties placeholder

我有一个属性文件并使用Spring属性占位符,我将值设置为Spring bean.现在,可以在运行时修改此属性文件.有没有办法用这个新修改的属性值刷新Spring bean的属性?特别是,我有很多单身豆?如何使用新值刷新它们?是否已有解决方案或是否应定制编码?如果它还不存在,有人可以提供最佳方法来实现这一目标吗?谢谢!

PS:我的应用程序是批处理应用程序.我使用基于Spring的Quartz配置来安排批次.

Sea*_*oyd 3

我会将其保留以供参考,但更新的答案位于分隔线下方:

好吧,该ConfigurableApplicationContext接口包含一个刷新()方法,这应该是您想要的,但问题是:如何访问该方法。无论采用哪种方式,您都将从具有 type 依赖项的 bean 开始ConfigurableApplicationContext

private ConfigurableApplicationContext context;
@Autowired
public void setContext(ConfigurableApplicationContext ctx){
    this.context = ctx;
}
Run Code Online (Sandbox Code Playgroud)

现在我建议的两个基本选项是

  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;
    }

}
Run Code Online (Sandbox Code Playgroud)

您可以将此属性 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);
    }

}
Run Code Online (Sandbox Code Playgroud)