最近在學習spring框架源碼,看到了其中涉及事件處理,打算研究下事件的實現(xiàn)方式,所以從頭學起,研究java中的事件實現(xiàn)機制。而且現(xiàn)實應用中很多都需要使用事件機制,而且使用事件機制也能對應用進行一定程度解耦。所以有必要好好了解下java中的事件機制。
場景假設
我們以網(wǎng)購12306火車票為場景,假設以下一些操作。
用戶購買火車票成功后,會觸發(fā)發(fā)送短信操作告知用戶買了哪個車的票。
用戶購買火車票成功后,會觸發(fā)發(fā)送郵件操作告知用戶買了哪個車的票。
重點理解
針對上面的場景,我們分析可以有如下幾個對象或操作。
1.火車票對象,2.購買成功發(fā)短信操作,3.購買成功發(fā)郵件操作。
事件概念理解:
事件源:觸發(fā)事件的對象,例如購買火車票成功后發(fā)短信的火車票就是就是事件源。
事件:對事件源進行操作產生的事件,例如購買成功后會產生發(fā)短信事件和發(fā)郵件事件。
事件監(jiān)聽器:對事件源產生的事件進行處理,可以對不同的事件設置不同的事件監(jiān)聽器,處理不同事件。
事件派發(fā)器:事件派發(fā)器主要處理事件的派發(fā)和事件監(jiān)聽器的管理,注冊和刪除事件監(jiān)聽器等。
目前java中EventObject對應事件,提供事件的基類,任何自定義事件都集成自該類;
EventListener對應事件監(jiān)聽器,提供事件監(jiān)聽器者接口,任何自定義的事件監(jiān)聽器都實現(xiàn)了該接口。
事件派發(fā)器java中沒有提供,需要自己去實現(xiàn)。
自己寫代碼實現(xiàn)
以網(wǎng)購火車票為例,整體代碼結構如圖

TrainTicket事件源類
package me.wiliam;
/**
* 事件源類
* @author wiliam
*
*/
public class TrainTicket {
private String userName;
private String ticketName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getTicketName() {
return ticketName;
}
public void setTicketName(String ticketName) {
this.ticketName = ticketName;
}
}
TrainTicketEvent購票事件基類
package me.wiliam;
import java.util.EventObject;
/**
* 購票事件基類
* @author wiliam
*
*/
public class TrainTicketEvent extends EventObject {
private static final long serialVersionUID = 1L;
public TrainTicketEvent(TrainTicket source) {
super(source);
}
}
SendEmailEvent發(fā)送郵件事件
package me.wiliam;
/**
* 發(fā)送郵件事件
* @author wiliam
*
*/
public class SendEmailEvent extends TrainTicketEvent {
private static final long serialVersionUID = 1L;
private TrainTicket trainTicket;
public SendEmailEvent(TrainTicket source) {
super(source);
this.trainTicket = source;
}
public TrainTicket getTrainTicket(){
return trainTicket;
}
public String getEmailData(){
if(trainTicket != null){
String data = "發(fā)送郵件:"+trainTicket.getUserName() + "您好,您已成功購買火車票"+trainTicket.getTicketName();
return data;
}
return "";
}
}
SendSMSEvent發(fā)送短信事件
package me.wiliam;
/**
* 發(fā)送短信事件
* @author huhailong
*
*/
public class SendSMSEvent extends TrainTicketEvent {
private static final long serialVersionUID = 1L;
private TrainTicket trainTicket;
public SendSMSEvent(TrainTicket source) {
super(source);
this.trainTicket = source;
}
public TrainTicket getTrainTicket(){
return trainTicket;
}
public String getSMSData(){
if(trainTicket != null){
String data = "發(fā)送短信:"+trainTicket.getUserName() + "您好,您已成功購買火車票"+trainTicket.getTicketName();
return data;
}
return "";
}
}
TrainTicketListener火車票事件監(jiān)聽器接口
package me.wiliam;
import java.util.EventListener;
/**
* 火車票事件監(jiān)聽器接口
* @author wiliam
*
*/
public interface TrainTicketListener extends EventListener {
void handEvent(TrainTicketEvent tte);
}
EmailAndSMSListener同時處理發(fā)送郵件事件和短信事件
package me.wiliam;
/**
* 同時處理發(fā)送郵件事件和短信事件
* @author wiliam
*
*/
public class EmailAndSMSListener implements TrainTicketListener {
@Override
public void handEvent(TrainTicketEvent tte) {
if(tte instanceof SendEmailEvent){
SendEmailEvent see = (SendEmailEvent)tte;
System.out.println(see.getEmailData());
}else if(tte instanceof SendSMSEvent){
SendSMSEvent sse = (SendSMSEvent)tte;
System.out.println(sse.getSMSData());
}else{
System.out.println("發(fā)送未知事件,無法處理");
}
}
}
config.properties配置文件
#靈活使用監(jiān)聽器,多個可以用逗號間隔
listener=me.wiliam.EmailAndSMSListener
TestBuyTrainTicketSuccessEvent事件測試類
package me.wiliam;
/**
* 事件測試類
* @author wiliam
*
*/
public class TestBuyTrainTicketSuccessEvent {
public static void main(String[] args) {
TestBuyTrainTicketSuccessEvent tbtts = new TestBuyTrainTicketSuccessEvent();
tbtts.buySuccessTicket();
}
private void buySuccessTicket(){
TrainTicket tt = new TrainTicket();
tt.setTicketName("【北京---濟南】");
tt.setUserName("小明");
System.out.println("購票成功");
TrainTicketPublisher.instance().publishEvent(new SendEmailEvent(tt));
TrainTicketPublisher.instance().publishEvent(new SendSMSEvent(tt));
}
}
運行上面的測試類,結果如下:
購票成功
發(fā)送郵件:小明您好,您已成功購買火車票【北京---濟南】
發(fā)送短信:小明您好,您已成功購買火車票【北京---濟南】
思考
首先如果想要增加其它的監(jiān)聽器,在配置文件中配置下就可以了。
針對上面的事件發(fā)布器中對事件監(jiān)聽的處理完全可以單獨啟動一個線程,一直監(jiān)聽事件隊列,有事件消息就處理,這樣就可以即時響應各種消息了,解耦一定的程序模塊。
代碼下載
代碼已上傳到我的github上:https://github.com/wiliam2015/EventDemo
想了解更多技術文章信息,請繼續(xù)關注wiliam.s Blog,謝謝,歡迎來訪!