2010-11-03 182 views
5

我有一個屬性文件並使用Spring屬性佔位符,我將值設置爲Spring bean。現在,這個屬性文件可能在運行期間被修改。有沒有辦法用這個新修改的屬性值來刷新Spring bean的屬性?特別是,我有很多單身豆?我怎樣才能用新的價值來刷新它們?是否已有解決方案或者是否應該定製編碼?如果它不存在,有人可以給出最好的方法來實現這一目標嗎?謝謝!Spring - 用新的屬性文件值替換bean屬性值

PS:我的應用程序是批量應用程序。我使用基於Spring的Quartz配置來安排批次。

回答

3

我會離開這個爲參考,但更新的答案是分隔器下方:

ConfigurableApplicationContext接口包含一個refresh()方法,這應該是你想要的,但問題是:如何訪問該方法。

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

現在我建議兩個基本的選擇是要麼

  1. 使用Task Execution Framework:你做哪種方式,將與具有ConfigurableApplicationContext類型的依賴豆開始並讓Bean定期查看屬性資源,當它發現更改時刷新ApplicationContext或
  2. expose the bean to JMX,允許您手動觸發刷新。

參考意見:因爲它似乎是不可能的刷新整個範圍內,另一種策略是創建一個屬性工廠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中,但是,您必須小心始終使用原型範圍。這在單身豆子裏特別棘手,a solution can be found here

如果你不希望所有的地方注入查找方法,你也可以注入PropertyProvider豆這樣的:

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

} 
+0

這是不是加載整個應用程序上下文?你能分享一些樣品嗎?我對Spring很新,所以我可能是錯的。我也想過重新加載整個Spring應用程序上下文,但這意味着其他當前正在運行的進程可能會中斷。或者,我想錯了! – SJoe 2010-11-03 08:50:24

+0

不,你是對的,整個上下文將被刷新。 – 2010-11-03 08:57:23

+0

在這種情況下,我目前正在運行的進程不會中斷。我的批處理應用程序可能需要數小時才能完成一個過程。另外,我有一個通過Spring配置的SchedularFactoryBean。我的問題是,如果我完全重新加載應用程序上下文,是不是會重置計劃程序?大概是 – SJoe 2010-11-03 09:07:49