摘要:  觀察者模式,定義對象之間的一種一對多的依賴關(guān)系,當(dāng)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都得到通知并且被自動更新。觀察者模式在JDK中有現(xiàn)成的實(shí)現(xiàn),java.util.Obserable。

  首先說下需求:通過ftp上傳約定格式的文件到服務(wù)器指定目錄下,應(yīng)用程序能實(shí)時(shí)監(jiān)控該目錄下文件變化,如果上傳的文件格式符合要求,將將按照每一行讀取解析再寫入到數(shù)據(jù)庫,解析完之后再將文件改名。(這個(gè)是原先已經(jīng)實(shí)現(xiàn)了的功能,請看我的一篇文章java利用WatchService實(shí)時(shí)監(jiān)控某個(gè)目錄下的文件變化并按行解析(注:附源代碼)

但項(xiàng)目上線一段時(shí)間后,發(fā)現(xiàn)再利用FileZilla登陸上傳文件,文件不能被解析,而重啟tomcat之后再上傳,又能解析,于是判定是監(jiān)控指定目錄的那個(gè)線程掛掉了,導(dǎo)致上傳后的文件不能被檢測到,故也不能被解析。之后查看日志也最終驗(yàn)證了我推斷。

  所以關(guān)鍵的問題就是:如何監(jiān)聽線程,當(dāng)意外退出線程后進(jìn)行自動重啟,這也是本文所要利用觀察者模式實(shí)現(xiàn)的。

下面請看實(shí)現(xiàn)過程(尤其見紅色注解部分):

  1、web.xml監(jiān)聽器配置文件監(jiān)控監(jiān)聽器,初始化創(chuàng)建一個(gè)監(jiān)控指定目錄的線程  

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

<?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監(jiān)聽器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>    <!-- 配置監(jiān)控文件變化監(jiān)聽器 -->    <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>

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

  2、編寫一個(gè)觀察者實(shí)現(xiàn)類,用于監(jiān)聽“監(jiān)控指定目錄線程”,當(dāng)“監(jiān)控指定目錄線程”掛掉后,自動重啟該線程

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

      ObserverListener  Log log = LogFactory.getLog(ObserverListener. "WatchFilePathTask掛掉"= "WatchFilePathTask重啟"

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

  3、編寫一個(gè)ThreadStartUpListenser類,實(shí)現(xiàn)ServletContextListener,tomcat啟動時(shí)創(chuàng)建后臺線程

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

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

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

  4、創(chuàng)建指定目錄文件變化監(jiān)控類WatchFilePathTask

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

  WatchFilePathTask  Observable  Log log = LogFactory.getLog(WatchFilePathTask.   String filePath = ConfigUtils.getInstance().getValue("userfile_path"
     ( 
            watchService ="獲取監(jiān)控服務(wù)"+="@@@: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");"啟動線程導(dǎo)入用戶數(shù)據(jù)"+"已經(jīng)到這里來了"

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

  5、創(chuàng)建解析用戶文件及導(dǎo)入數(shù)據(jù)庫線程,由WatchFilePathTask啟動

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

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(":@@@準(zhǔn)備開始休眠10秒鐘:" + file);            //休眠十分鐘,防止文件過大還沒完全拷貝到指定目錄下,這里的線程就開始讀取文件
            try {
                sleep(10000);
            } catch (InterruptedException e1) {
                e1.printStac

http://www.cnblogs.com/zishengY/p/7056948.html