我在 Spring 3 中使用属性文件。当 Spring 初始化其上下文时,它会加载属性文件并将其放入带有 @Value 注释的所有 bean 中。
我希望有可能更新文件中的某些属性,并在服务器上公开一个 JMX,它将新属性重新加载到 Spring - 无需重新启动服务器并重新加载其上下文。
我可以通过使用一些Spring 方法重新加载属性并将它们填充到所有 bean 来实现这一点,还是我应该自己编写类似的东西?
我在 Spring 3 中使用属性文件。当 Spring 初始化其上下文时,它会加载属性文件并将其放入带有 @Value 注释的所有 bean 中。
我希望有可能更新文件中的某些属性,并在服务器上公开一个 JMX,它将新属性重新加载到 Spring - 无需重新启动服务器并重新加载其上下文。
我可以通过使用一些Spring 方法重新加载属性并将它们填充到所有 bean 来实现这一点,还是我应该自己编写类似的东西?
我建议用Apache Commons Configuration项目中java.util.Properties
的 a替换。它支持自动重新加载,通过检测文件何时更改或通过 JMX 触发。PropertiesConfiguration
我认为没有通用的方法可以做到这一点。最“干净”的方法是关闭 Spring 上下文并从头开始构建它。例如,考虑使用 DBCP 连接池并更新它的数据库连接 URL。这意味着必须正确关闭池,然后必须创建新对象,然后还必须更新对池的所有引用。现在,一些 bean 可能会从该池中获取连接,并且更新池配置意味着您需要以某种方式重新请求连接。因此,bean 可能需要知道如何做到这一点,这并不常见。
我建议使用配置和更新事件创建单独的 bean,并将该 bean 作为您需要了解配置更改的所有 bean 的依赖项。然后,您可以使用 Apache Commons Configuration 来监视文件更改并传播配置更新。
也许使用 JMS 很好(如果您以后要分发您的应用程序)。
是的,您可以使用 Spring JMX 方式执行此操作。将这些 bean 添加到您的 spring 配置文件中。创建一个单独的方法来读取属性文件。在此示例中,我使用 callThisAgain() 方法。
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="your.package.bean:name=sampleBeanService" value-ref="sampleService"/>
</map>
</property>
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
<property name="managedMethods">
<value>
callThisAgain <!--Simply declare the method name here (only the name) -->
</value>
</property>
</bean>
</property>
</bean>
<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="rmiRegistry">
<property name="objectName" value="connector:name=rmi"/>
<property name="serviceUrl" value="service:jmx:rmi://127.0.0.1/jndi/rmi://127.0.0.1:11000/sample"/>
</bean>
<bean id="rmiRegistry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="11000"/>
</bean>
之后,您可以使用 jconsole 重新加载您的方法,而无需重新启动服务器。
Apache 为我们提供了使用可重新加载属性文件的实用程序。
<bean id="propertiesReloadingStrategy" class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy">
<property name="refreshDelay" value="30000" /> <!-- 30 seconds -->
</bean>
<bean id="reloadableProperties" class="org.apache.commons.configuration.PropertiesConfiguration">
<constructor-arg value="file:/web/${weblogic.Domain}/${weblogic.Name}/${app.Name}/reloadable_cfg/Reloadable.properties"/>
<property name="reloadingStrategy" ref="propertiesReloadingStrategy"/>
</bean>
使用 spring 常见的 apache 如下:
@Component
public class ApplicationProperties {
private PropertiesConfiguration configuration;
@PostConstruct
private void init() {
try {
String filePath = "/opt/files/myproperties.properties";
System.out.println("Loading the properties file: " + filePath);
configuration = new PropertiesConfiguration(filePath);
//Create new FileChangedReloadingStrategy to reload the properties file based on the given time interval
FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
fileChangedReloadingStrategy.setRefreshDelay(60*1000);
configuration.setReloadingStrategy(fileChangedReloadingStrategy);
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
public String getProperty(String key) {
return (String) configuration.getProperty(key);
}
public void setProperty(String key, Object value) {
configuration.setProperty(key, value);
}
public void save() {
try {
configuration.save();
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
}
虽然这里有些人建议使用外部方式来使用属性(Spring 自己使用属性文件的方式之外)。这个答案正是您正在寻找的https://stackoverflow.com/a/52648630/39998 Spring Boot 和 Java EE 中的热重载属性。