《Java Spring框架》SpringBoot 自定義監聽器(含模擬實現監聽管理器)


前言

在實際工作的過程,我們經常需要監聽一個任務實際完成的情況和進度。所以引入監聽器的概念。

案例

下面代碼都是在Spring Boot 框架下完成

設計一個任務:本任務簡單設置:一個循環,每次循環都發布一下進度情況。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class EventProcess {

    @Autowired
    private ApplicationContext applicationContext;

    public void process(){
        for(int i = 1; i <= 10; i++){
            try {
                /**** 為了演示效果睡眠一秒 ****/
                Thread.sleep(1000L);
                applicationContext.publishEvent(new CustomEvent(this,i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

設置一個外部需要關心內容的類

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent {

    private int index;
    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public CustomEvent(Object source,int index) {
        super(source);
        this.index = index;
    }

    public int getIndex() {
        return index;
    }
}

再設置一個監聽器:重寫onApplicationEvent 方法,並且將事件處理成前端可以識別的內容。

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomApplicationListener implements ApplicationListener<CustomEvent> {

    private String msg;

    @Override
    public void onApplicationEvent(CustomEvent event) {
        msg = "第"+event.getIndex()+"輪";
        System.out.println(msg);
    }

    public String getMsg() {
        return msg;
    }
}

controller 設置請求

import com.example.event.CustomApplicationListener;
import com.example.event.EventProcess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController2 {


    @Autowired
    EventProcess eventProcess;

    @Autowired
    CustomApplicationListener customApplicationListener;

    @RequestMapping("/event.do")
    public String event(){
        eventProcess.process();
        return "success";
    }

    @RequestMapping("/listener.do")
    public String listener(){
        return customApplicationListener.getMsg();
    }
}

測試:

 

 先請求event 讓任務跑起來。

 

 再請求listener 可以顯示現在任務的進度 。

原理(手寫監聽管理器)

以下內容不需要任務框架,只需要JDK即可

public class AEvent extends ApplicationEvent {

}
public class ApplicationEvent {
}
public class BEvent extends ApplicationEvent {
}
/**
 * 文件上傳事件
 */
public class FileUploadEvent extends ApplicationEvent {

    private int fileSize;

    private int readSize;

    public FileUploadEvent(int fileSize, int readSize) {
        this.fileSize = fileSize;
        this.readSize = readSize;
    }

    public int getFileSize() {
        return fileSize;
    }

    public int getReadSize() {
        return readSize;
    }
}
import demo.knowledgepoints.monitor.event.AEvent;

public class AAListener implements ApplicationListener<AEvent> {
    @Override
    public void onEvent(AEvent aEvent) {
        System.out.println("AA也監聽到了");
    }
}
import demo.knowledgepoints.monitor.event.AEvent;

public class AListener  implements ApplicationListener<AEvent>{
    @Override
    public void onEvent(AEvent aEvent) {
        System.out.println("監聽到了A事件");
    }
}
import demo.knowledgepoints.monitor.event.ApplicationEvent;

/**
 * 這里定義泛型是為了后面統一方法監聽的時候獲取實現該接口上設置的具體事件
 * @param <E>
 */
public interface ApplicationListener< E extends ApplicationEvent> {
    void onEvent(E e);
}
import demo.knowledgepoints.monitor.event.BEvent;

public class BListener implements ApplicationListener<BEvent> {
    @Override
    public void onEvent(BEvent bEvent) {
        System.out.println("監聽到了B事件");
    }
}
import demo.knowledgepoints.monitor.event.FileUploadEvent;

public class FileUploadListener implements ApplicationListener<FileUploadEvent> {
    @Override
    public void onEvent(FileUploadEvent event) {
        double i1 = event.getFileSize();
        double d = event.getReadSize()/i1;
        /*********
         * 正常情況這邊應該將值保存下來放入一個靜態變量中,
         * 然后前端訪問的時候將這個靜態變量返回給前端。
         *********/
        System.out.println("當前文件上傳進度百分比:"+d*100+"%");
    }
}

最重要的一步

import demo.knowledgepoints.monitor.event.ApplicationEvent;
import demo.knowledgepoints.monitor.listener.ApplicationListener;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

/**
 * 事件管理器
 */
public class ListenerManage {

    //保存所有的監聽器
    public static List<ApplicationListener<?>> list = new ArrayList<>();

    /**
     * Spring Boot 是掃描項目添加事件的
     * @param listener
     */
    public static void  addListener(ApplicationListener listener){
        list.add(listener);
    }

    /**
     * 監聽事件
     * @param event
     */
    public static void pushEvent(ApplicationEvent event){
        for (ApplicationListener applicationListener : list) {
            /**********獲取泛型的類型************/
            Class tClass = (Class)((ParameterizedType)applicationListener.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
            if (tClass.equals(event.getClass())) {
                applicationListener.onEvent(event);
            }
        }
    }
}

文件上傳監聽測試:

import demo.knowledgepoints.monitor.event.FileUploadEvent;
import demo.knowledgepoints.monitor.listener.FileUploadListener;
import demo.knowledgepoints.monitor.manage.ListenerManage;

import java.io.*;

public class FileUtil {

    public static int READ_SIZE= 100;

    public static void fileWrite(InputStream is, OutputStream os) throws Exception{
        BufferedInputStream bis = new BufferedInputStream(is);
        BufferedOutputStream bos  = new BufferedOutputStream(os);
        //文件總大小
        int fileSize = is.available();
        //一共讀取了多少
        int readSize = 0;
        byte[] b = new byte[READ_SIZE];
        boolean flag = true;
        while (flag){
            //文件實在小於第一次讀的時候
            if (fileSize<READ_SIZE){
                byte[] bytes = new byte[fileSize];
                bis.read(bytes);
                bos.write(bytes);
                readSize = fileSize;
                flag = false;
            }else if(fileSize<readSize+READ_SIZE){
                byte[] bytes = new byte[fileSize-readSize];
                readSize = fileSize;
                bis.read(bytes);
                bos.write(bytes);
                flag = false;
            }else{
                bis.read(b);
                readSize +=READ_SIZE;
                bos.write(b);
            }
            ListenerManage.pushEvent(new FileUploadEvent(fileSize,readSize));
        }
        bis.close();
        bos.close();
    }

    public static void main(String[] args) throws Exception {
        ListenerManage.addListener(new FileUploadListener());
        fileWrite(new FileInputStream(new File("src\\demo\\knowledgepoints\\monitor\\file\\a.txt")),new FileOutputStream(new File("src\\demo\\knowledgepoints\\monitor\\file\\b.txt")));
    }
}

運行結果:

監聽其他事件

import demo.knowledgepoints.monitor.event.AEvent;
import demo.knowledgepoints.monitor.event.BEvent;
import demo.knowledgepoints.monitor.listener.AAListener;
import demo.knowledgepoints.monitor.listener.AListener;
import demo.knowledgepoints.monitor.listener.BListener;
import demo.knowledgepoints.monitor.manage.ListenerManage;

import java.util.Scanner;

public class OtherListenerUtil {
    public static void main(String[] args) {
        ListenerManage.addListener(new AListener());
        ListenerManage.addListener(new BListener());
        ListenerManage.addListener(new AAListener());
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("選擇你要監聽的對象(A,B):");
            String scan = scanner.next();
            if (scan.equals("A")){
                ListenerManage.pushEvent(new AEvent());
            }else if (scan.equals("B")){
                ListenerManage.pushEvent(new BEvent());
            }
        }
    }
}

運行結果:

總結

監聽器是監聽任務是否正常運行,spring 本身也有內部不少事件需要被監聽:

  • 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發布。也可以在調用ConfigurableApplicationContext接口中的refresh()方法時被觸發。
  • 上下文開始事件(ContextStartedEvent):當容器ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
  • 上下文停止事件(ContextStoppedEvent):當容ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
  • 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
  • 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM