Quartz任務排程,訪問Servlet Context容器中的資料
Quartz任務排程,訪問Servlet Context容器中的資料
2014年08月07日 18:55:37
閱讀數:1102
Quartz是一種功能豐富的開源作業排程庫,它可以在幾乎任何Java應用程式整合,從最小的單機應用到最大的電子商務系統。 Quartz可以用來建立簡單或複雜的任務,排程執行數以十計,數百計,甚至成千上萬的任務。這些擁有某種Task的Job被定義為標準的Java元件,可以執行幾乎任何你可以程式設計實現的事情。 Quartz排程包括了許多企業級功能,如JTA事務和叢集支援。
Quartz是可免費使用,根據Apache2.0許可證授權。
官網地址:
問題背景:
因為做專案需要,對於登入次數超過一定數量的使用者,系統要判定為惡意登入,應該對那個賬號暫時性的鎖定,鎖定時間內此賬號是不能再次進行登入請求的,這樣可以有效減輕惡意登入情況。
之前想到的一個簡單辦法是session中計數,但是後來立馬被自己否定了,原因有幾個:
使用者換一個瀏覽器session值就改變了,也就可以再次用被鎖定的賬號;
即便如此,session失效的時間是系統啟動時就配置好了,不可控,比如我想鎖定時間設定成3個小時。
解決方案:
採用Servlet Context上下文儲存,用一個Map儲存鎖定使用者資訊,key為使用者名稱,value為鎖定開始時間,然後把Map儲存在Servlet上下文中。採用Quartz任務排程定時掃描鎖定列表,將達到解鎖時間的使用者移除。
因為之前未深入瞭解Quartz,遇到了一個問題,就是不知道怎麼讓任務中訪問到Servlet Context物件,spring和Quartz繼承後,在配置檔案中定義的排程任務也沒法訪問到Servlet 上下文(至少是在我寫此博文時,我還沒想來)。查閱了官網使用文件,介紹的任務都是較為簡單不用和Servlet上下文互動。x網上介紹Quartz和Servlet互動的部落格不多,於是自己花時間研究原始碼。
org.quartz.ee.servlet.QuartzInitializerListener或者org.quartz.ee.servlet.QuartzInitializerServlet類,原話是這麼說的——A ServletContextListner that can be used to initialize Quartz.,也就是說採用ServletContextListner或者HttpServlet這兩種方式來初始化Quartz排程器。
我在專案中採用的是第一種方式,繼承QuartzInitializerListener監聽器類,具體如下:
-
<span style="font-family:Microsoft YaHei;font-size:14px;">public class MyQuartzContextListener extends QuartzInitializerListener {
-
static final Logger logger = LogManager.getLogger(MyQuartzContextListener.class);
-
@Override
-
public void contextInitialized(ServletContextEvent sce) {
-
super.contextInitialized(sce);
-
ServletContext servletContext = sce.getServletContext();
-
//scheduler factory
-
StdSchedulerFactory sFactory = (StdSchedulerFactory)servletContext.getAttribute(QUARTZ_FACTORY_KEY);
-
Scheduler scheduler = null;
-
try {
-
scheduler = sFactory.getScheduler();
-
//定義一個JobDetail
-
JobDetail jobDetail = new JobDetail("lockedUserJobDetail", "lockedUserGroup", LockedUserMonitor.class);
-
// 將ServletContext物件放到map中,然後從job中取出來,從而取得路徑
-
Map<String, Object> map = new HashMap<String, Object>();
-
map.put("servletContext", servletContext);
-
//將servlet上下文新增到JobDataMap中
-
JobDataMap dateMap = new JobDataMap(map);
-
jobDetail.setJobDataMap(dateMap);
-
//觸發器
-
Trigger trigger = new CronTrigger("lockedUserCronTrigger", "lockedUserCronTrigger", "0 0/1 * ? * *");
-
//關聯任務和觸發器
-
scheduler.scheduleJob(jobDetail, trigger);
-
//開啟排程
-
scheduler.start();
-
} catch (SchedulerException e) {
-
logger.error("排程器 MyQuartzContextListener", e);
-
e.printStackTrace();
-
} catch (ParseException e) {
-
logger.error("排程器 CronTrigger表示式解析錯誤", e);
-
e.printStackTrace();
-
}
-
}
-
}</span>
在web.xml配置檔案新增
-
<span style="font-family:Microsoft YaHei;font-size:14px;"><!-- 任務排程監聽器 -->
-
<listener>
-
<listener-class>com.marketing.listener.MyQuartzContextListener</listener-class>
-
</listener></span>
然後是任務具體實現類,實現org.quartz.job.Job介面
-
<span style="font-family:Microsoft YaHei;font-size:14px;">public class LockedUserMonitor implements Job {
-
static final Logger logger = LogManager.getLogger(MyQuartzContextListener.class);
-
static final Long LOCKED_USER_LAST_TIME = 1000 * 60 * 60L;
-
@SuppressWarnings("unchecked")
-
@Override
-
public void execute(JobExecutionContext context) throws JobExecutionException {
-
ServletContext sevletContext = null;
-
//job data
-
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
-
//提取servlet context 物件
-
sevletContext = (ServletContext)jobDataMap.get("servletContext");
-
Object lockedUsers = sevletContext.getAttribute(AgencyConstant.AGENCY_LOGIN_FAILED_USER_MAP);
-
System.out.println("lockedUsers : "+ lockedUsers);
-
if( lockedUsers != null ) {
-
Map<String, Long> lockedUserMap = (HashMap<String,Long>)lockedUsers;
-
checkLockedUsersStatus( lockedUserMap );
-
}
-
}
-
/**
-
* 將超時的使用者接觸鎖定
-
* @param lockedUserMap
-
*/
-
private void checkLockedUsersStatus( Map<String,Long> lockedUserMap ) {
-
Set<Entry<String, Long>> userEntry = lockedUserMap.entrySet();
-
Iterator<Entry<String, Long>> userIt = userEntry.iterator();
-
Set<String> removeUsers = new HashSet<String>();
-
while( userIt.hasNext() ) {
-
Entry<String, Long> item = userIt.next();
-
String username = item.getKey();
-
Long lockedTime = item.getValue();
-
Long difference = lockedTime - System.currentTimeMillis();
-
if( difference >= LOCKED_USER_LAST_TIME ) {
-
removeUsers.add( username );
-
logger.info("當地時間:" + new Date(System.currentTimeMillis()) + ",使用者 [" + username +"]接觸登入鎖定");
-
}
-
}
-
//移除已經鎖定超過1小時的使用者
-
Iterator<String> it = removeUsers.iterator();
-
while( it.hasNext() ) {
-
lockedUserMap.remove( it.next() );
-
}
-
}
-
}</span>
在Job中,通過JobDetail的JobDataMap獲取到之前新增進去的Servlet Context物件引用,這樣就可以操作上下文了。
通過配置檔案配置的任務排程器,很方便。但是我這個地方需要在任務中訪問到Servlet上下文,對整個應用進行控制,想到的解決方案如上所示。
在此記錄,僅供學習,大家多多交流,共同進步~
文章標籤: quartzservlet任務排程quartz和Servlet互動
https://blog.csdn.net/chenjing502/article/details/38423251