Quartz任务调度,访问Servlet Context容器中的数据
2014-08-07 18:55
246 查看
Quartz是一种功能丰富的开源作业调度库,它可以在几乎任何Java应用程序集成,从最小的单机应用到最大的电子商务系统。 Quartz可以用来创建简单或复杂的任务,调度执行数以十计,数百计,甚至成千上万的任务。这些拥有某种Task的Job被定义为标准的Java组件,可以执行几乎任何你可以编程实现的事情。 Quartz调度包括了许多企业级功能,如JTA事务和集群支持。
Quartz是可免费使用,根据Apache2.0许可证授权。
官网地址:Quartz
问题背景:
因为做项目需要,对于登录次数超过一定数量的用户,系统要判定为恶意登录,应该对那个账号暂时性的锁定,锁定时间内此账号是不能再次进行登录请求的,这样可以有效减轻恶意登录情况。
之前想到的一个简单办法是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监听器类,具体如下:
在web.xml配置文件添加
然后是任务具体实现类,实现org.quartz.job.Job接口
在Job中,通过JobDetail的JobDataMap获取到之前添加进去的Servlet Context对象引用,这样就可以操作上下文了。
通过配置文件配置的任务调度器,很方便。但是我这个地方需要在任务中访问到Servlet上下文,对整个应用进行控制,想到的解决方案如上所示。
在此记录,仅供学习,大家多多交流,共同进步~
Quartz是可免费使用,根据Apache2.0许可证授权。
官网地址:Quartz
问题背景:
因为做项目需要,对于登录次数超过一定数量的用户,系统要判定为恶意登录,应该对那个账号暂时性的锁定,锁定时间内此账号是不能再次进行登录请求的,这样可以有效减轻恶意登录情况。
之前想到的一个简单办法是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上下文,对整个应用进行控制,想到的解决方案如上所示。
在此记录,仅供学习,大家多多交流,共同进步~
相关文章推荐
- Quartz任务中调用Spring容器中bean及动态调度任务
- Quartz(二)整合Spring容器中bean及动态调度任务
- Quartz()整合Spring容器中bean及动态调度任务
- Quartz(二)整合Spring容器中bean及动态调度任务
- Quartz任务中调用Spring容器中bean及动态调度任务
- 在spring中使用quartz进行任务调度遇到的问题
- Quartz任务调度模型实例
- 在Spring框架中集成Quartz实现任务调度
- Quartz 任务调度:初体验
- quartz结合spring轻松实现任务调度
- Spring框架结合Quartz实现任务调度实例
- Spring框架对QUARTZ任务调度组件的扩展支持实践小结
- Quartz任务调度
- Spring-Quartz 任务调度理所当然的陷阱
- Quartz任务调度快速入门
- quartz 关联多个 JobDetail和SimpleTrigger 多任务调度
- spring 任务调度 石英(Quartz) 表达式
- Quartz任务调度的使用(lp)
- List容器存储对话框控件句柄,并访问list数据设置控件文本
- WPF跨线程访问线程安全的数据(如解决:该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection)