摘要:  观察者模式,定义对象之间的一种一对多的依赖关系,当对象的状态发生改变时,所有依赖于它的对象都得到通知并且被自动更新。观察者模式在JDK中有现成的实现,java.util.Obserable。

  首先说下需求:通过ftp上传约定格式的文件到服务器指定目录下,应用程序能实时监控该目录下文件变化,如果上传的文件格式符合要求,将将按照每一行读取解析再写入到数据库,解析完之后再将文件改名。(这个是原先已经实现了的功能,请看我的一篇文章java利用WatchService实时监控某个目录下的文件变化并按行解析(注:附源代码)

但项目上线一段时间后,发现再利用FileZilla登陆上传文件,文件不能被解析,而重启tomcat之后再上传,又能解析,于是判定是监控指定目录的那个线程挂掉了,导致上传后的文件不能被检测到,故也不能被解析。之后查看日志也最终验证了我推断。

  所以关键的问题就是:如何监听线程,当意外退出线程后进行自动重启,这也是本文所要利用观察者模式实现的。

下面请看实现过程(尤其见红色注解部分):

  1、web.xml监听器配置文件监控监听器,初始化创建一个监控指定目录的线程  

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

<?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>

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  2、编写一个观察者实现类,用于监听“监控指定目录线程”,当“监控指定目录线程”挂掉后,自动重启该线程

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

      ObserverListener  Log log = LogFactory.getLog(ObserverListener. "WatchFilePathTask挂掉"= "WatchFilePathTask重启"

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  3、编写一个ThreadStartUpListenser类,实现ServletContextListener,tomcat启动时创建后台线程

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  ThreadStartUpListenser   WatchFilePathTask r =  Log log = LogFactory.getLog(ThreadStartUpListenser.  = 
            log.info("ImportUserFromFileTask is started!"

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  4、创建指定目录文件变化监控类WatchFilePathTask

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  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");"启动线程导入用户数据"+"已经到这里来了"

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  5、创建解析用户文件及导入数据库线程,由WatchFilePathTask启动

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

网友评论

更多精彩分享

万码学堂联系方式-Java培训机构,青岛Java培训,青岛计算机培训,软件编程培训,seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训,Java培训万码学堂联系方式