`

Java自动重载Spring配置文件

    博客分类:
  • Tool
阅读更多
系统中有些配置文件,修改后需要重启应用,这很让人苦恼,也很无奈,谁叫他只加载一次。
下面涉及动态加载配置文件。
需求如下:
         “如果配置文件有改动,自动加载配置文件,重配Spring加载”
需要监控目录下的文件是否变更,可以设置监控间隔时间,比如我这配置发上去,1分钟后自动生效,具体的生效时间可自定义.
代码如下,借助commons-io.jar,毕竟重复造轮子不是我的最爱.
package com.ycl.filter.FileCleaner;

import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;

/**
 * 监控类.
 * @author yangchunlong.tw
 *
 */
public class FileMonitor {

	FileAlterationMonitor monitor = null;

	/**
	 * 默认10妙看一次
	 * @param ob
	 */
	public FileMonitor(FileAlterationObserver ob){
		this(10000,ob);
	}

	/**
	 * 每隔多少时候看一次,观察者
	 * @param fileName
	 * @param ob
	 */
	public FileMonitor(long interval,FileAlterationObserver ob){
		monitor = new FileAlterationMonitor(interval,new FileAlterationObserver[]{ob});
	}

	/**
	 * 添加观察者
	 * @param observer
	 */
	public void addObserver(FileAlterationObserver observer){
		monitor.addObserver(observer);
	}

	/**
	 * 移除观察者
	 * @param observer
	 */
	public void removeObserver(FileAlterationObserver observer){
		monitor.removeObserver(observer);
	}

	/**
	 * 获取所有观察者
	 * @return
	 */
	public Iterable<FileAlterationObserver> getObservers() {
		return monitor.getObservers();
	}

	/**
	 * 启动监控[observer.initialize()]
	 */
	public void start(){
		try {
			monitor.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 停止监控[observer.destroy()]
	 */
	public void stop(){
		try {
			monitor.stop();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * [不做调用]
	 * 具体的监控操作:
	 *     observer.checkAndNotify()
	 */
	private void run(){
		monitor.run();
	}


}


以上是文件监控类,其中涉及到观察者,观察者如下:
package com.ycl.filter.FileCleaner;

import java.io.File;
import java.io.FileFilter;

import org.apache.commons.io.IOCase;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationObserver;

public class FileObserver extends FileAlterationObserver{

	private static final long serialVersionUID = 3637219592248717850L;

	/**
	 * 设置观查的文件对象/路径对象
	 * @param directory
	 */
	public FileObserver(String directory) {
		this(new File(directory),(FileFilter)null);
	}

	/**
	 * 设置观查的文件路径,带文件过滤器,比如所有xml文件.
	 *     这里的IOCase是设置文件比较器(排序).[根据系统,可以不用理会]
	 * @param directoryName
	 * @param fileFilter
	 */
	public FileObserver(File fileName, FileFilter fileFilter){
		super(fileName,fileFilter,(IOCase)null);
	}

	/**
	 * 监控启动时初始化方法
	 *   1. 刷新本文件对象
	 *   2. 得到本文件列表
	 *   3. 循环初始化File实体
	 *   4. 设置本文件以及其下的上下级关系
	 */
	 public void initialize() throws Exception {
		super.initialize();
	 }

	 /**
	  * 停止监控
	  * 	默认啥都没做
	  */
	 public void destroy() throws Exception {
		 super.destroy();
	 }


	 /**
	  * 监测文件有没有创建,修改,删除
	  *        并触发相应监听
	  *        如果文件名称比原先的大,那么创建一个实体,并调用onDirectoryCreate/onFileCreate
	  *        如果文件名称比原先的小,那么删除一个实体,并调用onDirectoryDelete/onFileDelete
	  *        如果文件名称和原告的一样,新的文件与原先的文件进行对比,如果文件属性有改变,并调用onDirectoryChange/onFileChange,循环调用自身,可能是文件夹
	  *        如果名称长度排在之后,添加文件,并调用onDirectoryCreate/onFileCreate
	  * 这样就注册了所有文件的监听器
	  */
	 public void checkAndNotify() {
		 super.checkAndNotify();
	 }

	 /**
	  * 添加监听器
	  */
	 public void addListener(final FileAlterationListener listener) {
		 super.addListener(listener);
	 }

	 /**
	  * 移除监听器
	  */
	 public void removeListener(final FileAlterationListener listener) {
		 super.removeListener(listener);
	 }


	 /**
	  * 获取观察者对象的所有监听器
	  */
	 public Iterable<FileAlterationListener> getListeners() {
		 return super.getListeners();
	 }

}


在观察者当中涉及到监听者,比如当文件变化了,有个监听者去执行相应的逻辑,比如重新加载Spring配置文件.
package com.ycl.filter.FileCleaner;

import java.io.File;

import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationObserver;

public class FileListener extends FileAlterationListenerAdaptor{

	@Override
	public void onDirectoryChange(File directory) {
		System.out.println("文件目录变更了:"+directory.getAbsolutePath());
	}

	@Override
	public void onDirectoryCreate(File directory) {
		System.out.println("文件目录创建了:"+directory.getAbsolutePath());
	}

	@Override
	public void onDirectoryDelete(File directory) {
		System.out.println("文件目录删除了:"+directory.getAbsolutePath());
	}

	@Override
	public void onFileChange(File file) {
		System.out.println("文件变更了:"+file.getAbsolutePath());
	}

	@Override
	public void onFileCreate(File file) {
		System.out.println("文件创建了:"+file.getAbsolutePath());
	}

	@Override
	public void onFileDelete(File file) {
		System.out.println("文件删除了:"+file.getAbsolutePath());
	}

	@Override
	public void onStart(FileAlterationObserver observer) {
		System.out.println("开始监听:"+observer.getDirectory());
	}

	@Override
	public void onStop(FileAlterationObserver observer) {
		System.out.println("停止监听:"+observer.getDirectory());
	}

}


万事俱备了,以下是测试代码:
package com.ycl.filter.FileCleaner;

public class TestFileMonitor {

	public static void main(String args[]){
		FileObserver ob = new FileObserver("D:\\test");
		FileListener listener = new FileListener();
		ob.addListener(listener);
		FileMonitor monitor = new FileMonitor(ob);
		monitor.start();
	}
}


监听某个目录下的文件,如果不需要监听,可以调用stop()方法。比如我可以在配置里面设置这个参数来控制是否需要动态加载Spring配置文件.
测试结果如下:
...
文件目录创建了:D:\test\bbb
停止监听:D:\test
开始监听:D:\test
文件目录删除了:D:\test\bbb
文件目录创建了:D:\test\新建文件夹
停止监听:D:\test
开始监听:D:\test
文件目录创建了:D:\test\cccc
文件目录删除了:D:\test\新建文件夹
停止监听:D:\test
开始监听:D:\test
文件创建了:D:\test\cccc\新建 文本文档.txt
停止监听:D:\test
开始监听:D:\test
文件创建了:D:\test\cccc\abc.test
文件删除了:D:\test\cccc\新建 文本文档.txt
停止监听:D:\test
开始监听:D:\test
文件删除了:D:\test\cccc\abc.test
文件目录删除了:D:\test\cccc
停止监听:D:\test

可以返复操作此目录下的文件或者文件夹,这里都能监听到此目录下文件的变化.
分享到:
评论
28 楼 wkshippou 2011-06-29  
包名大写,牛白!
27 楼 richit 2011-06-25  
kyfxbl 写道
脱离需求啊,有什么场景会边跑边改spring配置文件吗?

还是有可能的,在Dev阶段,大项目的时候,分层很多,配置文件很多,有时候不免会忘记配置一些类。
26 楼 坏孩子 2011-06-24  
a123159521 写道
如果只是java文件修改了,如何加载。。。
feiyu86 写道
能写下具体怎么加载吗?
如果只是java文件修改了,如何加载。。。

具体的加载方式需要了解Spring对bean的生命周期,我说下思路,具体的自已去实现。
如果文件是新加的xml,则可以新建一个Application,指定其父Application.
如果文件是删除的xml,则可以销毁一个Application.
如果文件是修改的xml,则需要检测文件的修改点,比哪BeanA做了变更,则可以重新加载BeanA,放设置到Application中,其中引用BeanA的Bean,如果需要更新的,则需要重新初始化它的引用。



你怎么知道bean对应的xml文件?反射获取还是改了spring的代码?
25 楼 feiyu86 2011-06-24  
jsjmz 写道
LZ 有个东西叫着 apache commons configuration
你可以使用之
e.g.
    <bean id="....config" class="org.apache.commons.configuration.XMLConfiguration">
        <constructor-arg type="java.lang.String" value="XXXX.xml"/>
        <property name="reloadingStrategy">
            <bean class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"/>
        </property>
    </bean>



回去研究下。
24 楼 a123159521 2011-06-24  
如果只是java文件修改了,如何加载。。。
feiyu86 写道
能写下具体怎么加载吗?
如果只是java文件修改了,如何加载。。。

具体的加载方式需要了解Spring对bean的生命周期,我说下思路,具体的自已去实现。
如果文件是新加的xml,则可以新建一个Application,指定其父Application.
如果文件是删除的xml,则可以销毁一个Application.
如果文件是修改的xml,则需要检测文件的修改点,比哪BeanA做了变更,则可以重新加载BeanA,放设置到Application中,其中引用BeanA的Bean,如果需要更新的,则需要重新初始化它的引用。
23 楼 feiyu86 2011-06-24  
能写下具体怎么加载吗?
如果只是java文件修改了,如何加载。。。
22 楼 坏孩子 2011-06-23  
楼主没有把如何重新加载bean的代码贴出来,直接刷整个context速度很慢,还不如直接重启
21 楼 xwf2010_good 2011-06-23  
开发的时候 自己修改配置以后 还不如写个main手动加载一下更方便。
20 楼 sking945 2011-06-23  
LZ,使用条件只有一个,那就是监听其他服务器是否正常使用。对于正在使用的服务,这样进行修改配置文件重新加载,肯定会出问题的。。。。
19 楼 newvirus 2011-06-23  
代码不错 不过实际应用中应用的很少 
18 楼 a123159521 2011-06-23  
BruceXX 写道
像这种非动态的还不靠谱。。。试下用spring加载groovy,ruby之类的。。

使用动态语言是不错的选择,这个也看你应用的场景。
现在有两种模式,一种是推,推就是说我有新闻,我会给每一家都发放报纸。[肯定有新闻]
                一种是拉,拉就是说只看浙江晚报,我去你家取。[可能没新闻]
比如,文件变化了,我告诉你我变化了,所有使用到我的关系户,你们监听到了,做相应的变更吧.
比如,文件变化了,我每一次去检测一下,有没有变化,如果变化了,我自己做相应的变更.
当然不同的需求,不同的业务,就会有不同的解决方案。
17 楼 a123159521 2011-06-23  
jsjmz 写道
LZ 有个东西叫着 apache commons configuration
你可以使用之
e.g.
    <bean id="....config" class="org.apache.commons.configuration.XMLConfiguration">
        <constructor-arg type="java.lang.String" value="XXXX.xml"/>
        <property name="reloadingStrategy">
            <bean class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"/>
        </property>
    </bean>

嗯,这个不错,应用了文件变更策略.
Spring重载bean为什么会产生多代的bean呢,不知道你有没有看过Spring的源码。bean一般只初始化一次,如果配置文件重载了,你覆盖以前的bean便是了.
如果业务逻辑正在处理,你把bean变更了,会不会对业务产生影响。Spring使用的是并发Map,支持多线程并发操作,如果当前业务得到的是“老”的bean,那么走“老”的逻辑,如果得到的“新”的bean,走的是“新”的逻辑.
16 楼 BruceXX 2011-06-23  
像这种非动态的还不靠谱。。。试下用spring加载groovy,ruby之类的。。
15 楼 xpfnihao 2011-06-23  
commons-io.jar能给我一个不?我觉着这个功能要是实现了,开发的时候就不用总重启了,耽误时间,想研究下
xpfnihao@163.com
14 楼 hpsysljt 2011-06-23  
楼主其实就是想实现一个类似wtp的动态加载配置文件的功能,提升开发效率,无关生产环境、需求之流
13 楼 JE帐号 2011-06-23  
问题有复杂化的倾向...
也就是说,运行一段时间后,你的Spring容器里会有第1次配置时的产生的bean以及第n次产生的bean.同时如果bean的scope又不同的话,或者scope不是singleton 这样的,同一个bean可能会有多个实现版本在运行,会不会引发一些冲突之类?

结果是,每次你发布spring配置文件的时候,除了要检查语义上的完备性,还给去检查业务与逻辑的冲突.这个责任由谁来负责?
12 楼 ferly_j 2011-06-23  
没看到跟spring有什么关系
11 楼 mayEyeInfo 2011-06-23  
支持楼主!虽然重载spring配置文件应用型不高,不过可以检测某些文件的改变!
10 楼 jsjmz 2011-06-23  
LZ 有个东西叫着 apache commons configuration
你可以使用之
e.g.
    <bean id="....config" class="org.apache.commons.configuration.XMLConfiguration">
        <constructor-arg type="java.lang.String" value="XXXX.xml"/>
        <property name="reloadingStrategy">
            <bean class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"/>
        </property>
    </bean>
9 楼 handong890 2011-06-23  
楼主可以看看jrebel是不是你需要的

相关推荐

    Spring面试题含答案.pdf

    12. Spring 配置文件 13. 什么是 Spring IOC 容器? 14. IOC 的优点是什么? 15. ApplicationContext 通常的实现是什么? 16. Bean 工厂和 Application contexts 有什么区别? 17. 一个 Spring 的应用看起来象什么...

    JAVA上百实例源码以及开源项目

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    Spring-Reference_zh_CN(Spring中文参考手册)

    13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form标签 ...

    greenbird-configuration:基于Spring的项目的配置框架

    使用常规Spring配置文件分隔环境。 活动配置文件的配置属性的自动重载。 特定于配置文件的属性可以在单独的文件中定义,也可以并排在单个文件中。 可以通过属性扩展在其他属性中引用配置值。 Spring属性占位符值和...

    JAVA上百实例源码以及开源项目源代码

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    DWR.xml配置文件说明书(含源码)

    spring Location* 任何以location开头的参数,每个参数都是指定一个spring的配置文件,在参数没有设置的情况下DWR会去读取spring的全局的配置文件. spring beanName 从配置文件中读取的bean的名称 “scope参数允许你...

    Java 基础核心总结 +经典算法大全.rar

    Java 开发环境配置 Java 基本语法 数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else if 多分支语句switch 多分支语句 循环语句 while 循环语句do...while 循环for 循环...

    Java语言基础下载

    方法重载(method overloading) 91 方法覆盖(method overriding) 93 基于继承的多态实现 94 隐藏(hiding) 95 构造方法在继承中的使用 96 super关键字 97 包装类 97 toString( )方法 100 内容总结 101 独立实践 102 第...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    著作:《java jdk 5.0学习笔记》、《java se 6技术手册》、《spring技术手册》等 译作:《ajax实战手册》、《jquery实战手册(第2版)》 个人网站:http://openhome.cc 目录 《java jdk 7学习笔记》 chapter1 ...

    Java面试宝典2020修订版V1.0.1.doc

    3、什么是TOMCAT,怎样启动停止,配置文件,日志文件的存储。 31 4、解释一下什么是servlet;什么是servlet容器; 32 5、说一说Servlet的生命周期,执行过程? 32 6、实例化servlet有几种方式 32 7、谈谈你对http协议的...

    java面试题

    2:Spring AOP:通过配置管理特性 3:Spring ORM:Spring框架集成了若干ORM框架 4:Spring DAO:打开关闭数据库连接 5:Spring WEB:为基于WEB服务的应用程序提供上下文服务 6:Spring Context:向Spring框架...

    Struts2属性文件详解

    该属性指定加载Struts 2配置文件的配置文件管理器.该属性的默认值是org.apache.Struts2.config.DefaultConfiguration, 这是Struts 2默认的配置文件管理器.如果需要实现自己的配置管理器,开发者则可以实现一个实现...

    Grails 中文参考手册

    12.8 参与自动重载 12.9 理解插件加载的顺序 13. Web服务 13.1 REST 13.2 SOAP 13.3 RSS和Atom 14. Grails和Spring 14.1 Grails的支柱 14.2 配置其他Bean 14.3 通过Beans DSL运行Spring 14.4 配置属性占位 14.5 配置...

    ReloadablePropertiesAnnotation:动态属性配置在运行时使用Java 7 WatchService API,Google Guava和Spring 3.2.5重新加载

    可重载属性注释一个简单的实用工具,它允许通过@ReloadableProperty批注从属性文件中设置对象字段。 如果给定的属性文件在运行时更改,这些属性也会自动重新加载。注释用法示例@ReloadableProperty("dynamicProperty...

    从J2SE到J2EE知识点介绍

    2. 通过web.xml配置文件访问servlet的流程 129 (七) servlet里面的跳转和传参数的方法 130 1. 跳转 130 2. 传参数 131 (八) jsp中文乱码问题 131 1. JSP页面乱码 132 2. 表单提交中文时出现乱码 134 3. 关于jsp在...

    quantum:社交媒体聚合器

    量子Quantum webapp在后端使用Spring Boot,在前端使用React,将Maven和Webpack作为构建工具,在两侧进行热重载,而无需进行xml配置。生产可以在这里找到应用程序-&gt; Com Hem:http: Boxer:http: 地位特拉维斯CI:...

    Grails权威指南

    第1章 寻找grails之旅  1.1 java的困惑 ... 11.3.2 重载bean的定义  11.4 在grails中使用spring控制器  11.5 在grails中使用acegi  11.6 使用xfire创建soap服务  11.7 本章小结

    Sosoo 1.0网络爬虫程序.doc

    设置要访问的url列表【allowedURLs】:这是一个Vector类型的变量,用户可以把这些url放在配置文件中,用户可以在运行时提供这个变量。 robby.setAllowedURLs(allowed); 定制url检查规则【URLCheck】:用户除了...

Global site tag (gtag.js) - Google Analytics