摘要: 观察者模式,定义对象之间的一种一对多的依赖关系,当对象的状态发生改变时,所有依赖于它的对象都得到通知并且被自动更新。观察者模式在JDK中有现成的实现,java.util.Obserable。
首先说下需求:通过ftp上传约定格式的文件到服务器指定目录下,应用程序能实时监控该目录下文件变化,如果上传的文件格式符合要求,将将按照每一行读取解析再写入到数据库,解析完之后再将文件改名。(这个是原先已经实现了的功能,请看我的一篇文章java利用WatchService实时监控某个目录下的文件变化并按行解析(注:附源代码))
但项目上线一段时间后,发现再利用FileZilla登陆上传文件,文件不能被解析,而重启tomcat之后再上传,又能解析,于是判定是监控指定目录的那个线程挂掉了,导致上传后的文件不能被检测到,故也不能被解析。之后查看日志也最终验证了我推断。
所以关键的问题就是:如何监听线程,当意外退出线程后进行自动重启,这也是本文所要利用观察者模式实现的。
下面请看实现过程(尤其见红色注解部分):
1、web.xml监听器配置文件监控监听器,初始化创建一个监控指定目录的线程
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:root-context.xml</param-value> </context-param> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>sitemesh</filter-name> <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置监控文件变化监听器 --> <listener> <listener-class>com.zealer.ad.listener.ThreadStartUpListenser</listener-class> </listener> <listener> <listener-class>com.zealer.ad.listener.SessionLifecycleListener</listener-class> </listener> <jsp-config> <taglib> <taglib-uri>/tag</taglib-uri> <taglib-location>/WEB-INF/tag/tag.tld</taglib-location> </taglib> </jsp-config> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <session-config> <session-timeout>45</session-timeout> </session-config> </web-app>
2、编写一个观察者实现类,用于监听“监控指定目录线程”,当“监控指定目录线程”挂掉后,自动重启该线程
ObserverListener Log log = LogFactory.getLog(ObserverListener. "WatchFilePathTask挂掉"= "WatchFilePathTask重启"
3、编写一个ThreadStartUpListenser类,实现ServletContextListener,tomcat启动时创建后台线程
ThreadStartUpListenser WatchFilePathTask r = Log log = LogFactory.getLog(ThreadStartUpListenser. = log.info("ImportUserFromFileTask is started!"
4、创建指定目录文件变化监控类WatchFilePathTask
WatchFilePathTask Observable Log log = LogFactory.getLog(WatchFilePathTask. String filePath = ConfigUtils.getInstance().getValue("userfile_path" ( watchService ="获取监控服务"+="@@@:Path:"+ String todayFormat = DateTime.now().toString("yyyyMMdd"= = existFiles.listFiles( ((todayFormat+".txt" ( != ImportUserFromFileTask task = (ImportUserFromFileTask) SpringUtils.getApplicationContext().getBean("importUserFromFileTask" WatchKey key = (= (WatchEvent<?> String fileName = ((todayFormat+".txt"= path.toFile().getAbsolutePath()+File.separator+"import filePath:"+ ImportUserFromFileTask task = (ImportUserFromFileTask) SpringUtils.getApplicationContext().getBean("importUserFromFileTask");"启动线程导入用户数据"+"已经到这里来了"
5、创建解析用户文件及导入数据库线程,由WatchFilePathTask启动
package com.zealer.ad.task;import com.zealer.ad.entity.AutoPutUser;import com.zealer.ad.entity.Bmsuser;import com.zealer.ad.service.AutoPutUserService;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.joda.time.DateTime;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.util.Date;import javax.annotation.Resource;/** * 解析用户文件及入库线程,由WatchFilePathTask启动 * @author cancer * */public class ImportUserFromFileTask extends Thread { private Log log = LogFactory.getLog(ImportUserFromFileTask.class); private String fileName; @Resource(name = "autoPutUserService") private AutoPutUserService autoPutUserService; @Override public void run() { File file = new File(fileName); if (file.exists() && file.isFile()) { log.debug(":@@@准备开始休眠10秒钟:" + file); //休眠十分钟,防止文件过大还没完全拷贝到指定目录下,这里的线程就开始读取文件 try { sleep(10000); } catch (InterruptedException e1) { e1.printStac
http://www.cnblogs.com/zishengY/p/7056948.html