This article describes job visualizations (management, imperfect visual management of this article) when using the job framework of spring (spring inherited and simplified quartz)
The solution is to use listeners to implement job history, job statistics, exception logging, manual trigger Job
Let's take a look at the implementation process
Here you only need to implement several listeners and register to
-Statisticschedulerlistener listener trigger rule triggers, typically triggered when spring starts and refreshes
-Statisticjoblistener Job Listener (monitor job before and after execution)
-Statistictriggerlistener
The main use of statisticjoblistener here
public class Statisticjoblistener implements Joblistener {private static Logger log = Logger.getlogger (statisticjobli
Stener.class);
private static threadlocal<jobstatisticbean> ThreadLocal = new threadlocal<jobstatisticbean> ();
private String name;
public void SetName (String name) {this.name = name;
} @Override Public String getName () {return this.name; }//beginging @Override public void jobtobeexecuted (Jobexecutioncontext context) {Log.info ("job will be executed. ..
"+context.getjobdetail (). GetName ());
Jobstatisticbean Jobstatisticbean = new Jobstatisticbean ();
Jobstatisticbean.setjobname (Context.getjobdetail (). GetName ());
Jobstatisticbean.setjobdetail (Context.getjobdetail ());
Jobstatisticbean.settrigger (Context.gettrigger ());
Jobstatisticbean.setstarttime (New Timestamp (System.currenttimemillis ()));
Jobstatisticbean.setjobexecutioncontext (context); JobstatIsticbean.setjobintance (Context.getjobinstance ());
Threadlocal.set (Jobstatisticbean); } @Override public void jobexecutionvetoed (Jobexecutioncontext context) {Log.info ("jobexecutionvetoed" +
Context.getjobdetail (). GetName ());
} @Override public void jobwasexecuted (Jobexecutioncontext context, jobexecutionexception jobexception) {
Log.info ("Job Execution Complete" +context.getjobdetail (). GetName ());
Jobstatisticbean Jobstatisticbean = Threadlocal.get ();
if (jobstatisticbean!=null) {jobstatisticbean.setendtime (New Timestamp (System.currenttimemillis ())); Jobstatisticbean.settakestime (Jobstatisticbean.getendtime (). GetTime ()-jobstatisticbean.getstarttime (). GetTime (
));
Statisticprocessor.add (Jobstatisticbean); }
}
}
The
specific cache can be extended by itself, which simply uses the current JVM cache and can expand Redis
public class Statisticprocessor extends Thread implements Applicationcontextaware, Initializingbean, Disposablebean {
private static Logger Logjob = Logger.getlogger (loggercategory.job_statistic);
private static Logger Logjobhistory = Logger.getlogger (loggercategory.job_statistic_history);
private static Logger logjobexception = Logger.getlogger (loggercategory.job_statistic_exception);
private static volatile queue<jobstatisticbean> Jobqueue = new concurrentlinkedqueue<jobstatisticbean> (); private static volatile queue<schedulerexceptionbean> Exceptionqueue = new concurrentlinkedqueue<
Schedulerexceptionbean> (); private static volatile map<string, jobstatisticbean> jobmap = new concurrenthashmap<string, jobstatisticbean&
gt; (); /** * Manual Trigger Job * @param Jobstatisticbean * @return * @throws Exception */public static Boolea N Runbyhand (Jobstatisticbean Jobstatisticbean) throws Exception{if (jobstatisticbean==null) return false;
Jobexecutioncontext context = Jobstatisticbean.getjobexecutioncontext ();
Job Job = Jobstatisticbean.getjobintance ();
Job.execute (context);
return true; }/** * Add an instance of the job (use map to prevent duplication) and record the job execution record (Queue) * @param jobstatisticbean * @return */Public
Static Boolean Add (Jobstatisticbean Jobstatisticbean) {if (!jobmap.containskey (Jobstatisticbean.getjobname ())) {
Logjob.info ("Add Job" + jacksonutil.tojsonstring (Jobstatisticbean));
} jobmap.put (Jobstatisticbean.getjobname (), Jobstatisticbean);
Logjobhistory.info (jacksonutil.tojsonstring (Jobstatisticbean));
Return Jobqueue.add (Jobstatisticbean); }/** * Add execution Exception Log * @param Schedulerexceptionbean * @return * */public static Boolean add (Sche Dulerexceptionbean Schedulerexceptionbean) {logjobexception.info (Jacksonutil.tojsonstring (SCHedulerexceptionbean));
Return Exceptionqueue.add (Schedulerexceptionbean);
} public static list<jobstatisticbean> getalljobs () {int size = Jobmap.size (); Size = size>100?
100:size;
Return Arrays.aslist (Jobmap.values (). ToArray (new jobstatisticbean[size]);
} public static list<jobstatisticbean> getalljobhistory () {int size = Jobqueue.size (); Size = size>100?
100:size;
Return Arrays.aslist (Jobqueue.toarray (new jobstatisticbean[size]));
} public static list<schedulerexceptionbean> getallexceptions () {int size = Exceptionqueue.size (); Size = size>100?
100:size;
Return Arrays.aslist (Exceptionqueue.toarray (new schedulerexceptionbean[size]));
} private Volatile Boolean exit = FALSE;
Private ApplicationContext applicationcontext = null;
private static volatile statisticprocessor processorintance = null;
Public synchronized void Init () { if (processorintance==null) {logjob.info ("---------------------" +new Date (). toLocaleString () + "----------
----------------");
Logjobhistory.info ("---------------------" +new Date (). toLocaleString () + "--------------------------");
Logjobexception.info ("---------------------" +new Date (). toLocaleString () + "--------------------------");
Processorintance = new Statisticprocessor ();
Processorintance.setname (Gconstants.threa_head + "jobstatisticprocessor");
Processorintance.setdaemon (TRUE);
Processorintance.start ();
}} @Override public void Run () {do{try {thread.sleep (1000*30); Synchronized (jobqueue) {if (!jobqueue.isempty ()) {Long outsize =
Jobqueue.size ()-100;
while (outsize--> 0) {jobqueue.poll (); }
}} synchronized (Exceptionqueue) {if (!exceptio
Nqueue.isempty ()) {Long outsize = exceptionqueue.size ()-100;
while (outsize--> 0) {exceptionqueue.poll ();
}}}}catch (Exception e) {e.printstacktrace ();
}}while (!this.exit);
} @Override public void Setapplicationcontext (ApplicationContext applicationcontext) throws Beansexception {
This.applicationcontext = ApplicationContext;
} @Override public void Afterpropertiesset () throws Exception {This.init ();
} @Override public void Destroy () {this.exit = true; }
}
public class Jobstatisticbean implements Serializable {
private static long serialversionuid = -1l;
Private String jobName;
Private String className;
Private Timestamp startTime;
Private Timestamp endTime;
Private Long takestime;
Private Jobdetail Jobdetail;
Private Trigger Trigger;
Private Jobexecutioncontext Jobexecutioncontext;
Private Job jobintance;
//.. Getter & Setter
}
Job.xml
<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" Xmlns:xs I= "Http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation= "Http://www.springframework.org/schema/beans Http://www.springframework.org/schema/beans/spring-beans-2.0.xsd "> <bean id=" Schedulerfactorybean "class=" Org.springframework.scheduling.quartz.SchedulerFactoryBean "lazy-init=" false "> <property name=" Schedulernam E "value=" Ezhe-taks "/> <property name=" triggers "> <list> <ref bean= "Task1"/> <ref bean= "Task2"/> </list> </property> <p Roperty name= "Globaljoblisteners" > <list> <bean class= "Com.gozap.ezhe.task.listen Er.
Statisticjoblistener "> <property name=" name "value=" Job statistics "/> </bean>
</list> </property> <property name= "Schedulerlisteners" > <list> <bea n class= "Com.gozap.ezhe.task.listener.StatisticSchedulerListener" > </bean> </list&
Gt </property> <property name= "Autostartup" value= "true"/> <property name= "Configlocation" Val Ue= "Classpath:quartz.properties"/> </bean> <!--automatically update the exchange rate task--<bean id= "Task1" class= "Org.spr Ingframework.scheduling.quartz.CronTriggerBean "> <property name=" jobdetail "> <bean id=" Jo Bupdatecurrencytask "class=" Org.springframework.scheduling.quartz.JobDetailBean "> <property name=" NA Me "value=" Automatically update the exchange rate task "/> <property name=" Jobclass "value=" Com.gozap.ezhe.task.CurrencyUpdateTask "> </property> </bean> </property> <property name= "cronexpression" value= "0 0/30 * * *?" /> </bean> <!--auto XX task--<bean id= "Task2" class= "Org.springframework.scheduling.quartz.Cro Ntriggerbean "> <property name=" jobdetail "> <bean id=" logisticsscheduletask "class=" org.sp
Ringframework.scheduling.quartz.JobDetailBean "> <property name=" name "value=" Auto xx task "/> <property name= "Jobclass" value= "Com.gozap.ezhe.task.LogisticsScheduleTask" ></property> &L t;/bean> </property> <property name= "cronexpression" value= "0 0 0/2 * *?" /> </bean> </beans>
Jobstatisticaction.java
public class Jobstatisticaction extends Baseaction {
private list<jobstatisticbean> joblist;
Private list<jobstatisticbean> jobhistorylist;
Private list<schedulerexceptionbean> jobexceptionlist;
Public String jobstatistic () throws Exception {
joblist = Statisticprocessor.getalljobs ();
Jobhistorylist = Statisticprocessor.getalljobhistory ();
Collections.reverse (jobhistorylist);
Jobexceptionlist = Statisticprocessor.getallexceptions ();
return action.success;
}
============================ public
list<jobstatisticbean> getjoblist () {
return joblist;
}
Public list<jobstatisticbean> getjobhistorylist () {
return jobhistorylist;
}
Public list<schedulerexceptionbean> getjobexceptionlist () {
return jobexceptionlist;
}
}
job.jsp
<%@ page contenttype= "Text/html;charset=utf-8" language= "java"%> <%@ taglib uri= "/struts-tags" prefix= "s"% > <%@ page import= "java.text.SimpleDateFormat"%> <%@ page import= "java.util.Date"%> <% Simpledatef Ormat SDF = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss.
SSS ");
String nowtime = Sdf.format (New Date ()); %>
This article describes just a simple implementation, recommend the use of design patterns in some way to refactor, if there is time later I will also refactor