Spring定时器的使用
Spring配置定时器(注解+xml)方式—整理
Spring配置定时器(注解+xml)⽅式—整理⼀、注解⽅式1. 在Spring的配置⽂件ApplicationContext.xml,⾸先添加命名空间1 xmlns:task="/schema/task"2 /schema/task3 /schema /task/springtask3.1.xsd42. 最后是我们的task任务扫描注解1<task:annotation-driven/>3. spring扫描位置1<context:annotation-config/>2<context:component-scan base-package="com.test"/>4.写⾃⼰的定时任务1 @Component //import ponent;2public class MyTestServiceImpl implements IMyTestService {3 @Scheduled(cron="0/5 * * * * ? ") //每5秒执⾏⼀次4public void myTest(){5 System.out.println("进⼊测试");6 }7 }♦注意:定时器的任务⽅法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定⼀个proxytargetclass的某个值为true)⼆、XML⽅式1.在spring配置⽂件中创建bean,创建schedule1<bean id="schedule"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">3<property name="triggers">4<list>5<ref bean="testTrigger"/>6</list>7</property>8</bean>2. 在spring配置⽂件中创建bean,创建你的triggers1<bean id="testTrigger"class="org.springframework.scheduling.quartz.CronTriggerBean">3<property name="jobDetail" ref="testJobDetail"/>4<property name="cronExpression" value="0 1/5 * * * ?"/>5</bean>3. 在spring配置⽂件中创建bean,指定定时器作⽤在那个类那个⽅法上⾯1<bean id="testJobDetail"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">3<property name="targetObject" ref="targetTestService"/>4<property name="targetMethod" value="timerTest"/>5</bean>♦注明:把定时器作⽤在targetTestService对象中的timerTest⽅法上⾯4. 当然还得把你作⽤的对象交Spring来管理,所以在spring配置⽂件中创建作⽤类的 bean1<bean id="targetTestService" class=".service.TargetTestService" scope="prototype"></bean>♦这是时间的设置规则org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运⾏时间,只需要设置其cronExpression属性。
Spring提供的三种定时任务机制及其比较
Spring提供的三种定时任务机制及其比较定时任务的需求在众多应用系统中广泛存在,在Spring中,我们可以使用三种不同的定时机制,下面一一描述并加以比较1. 基于Quartz的定时机制下面详细解释这个类图中涉及的关键类及其使用场景1.1. SchedulerFactoryBean这是Spring中基于Quartz的定时机制入口,只要Spring容器装载了这个类,Quartz定时机制就会启动,并加载定义在这个类中的所有triggerSpring配置范例:[xhtml]view plaincopy1.<bean id="sfb"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">2.<!-- 添加触发器 -->3.<property name="triggers">4.<list>5.<ref local="appSubscTrigger"/>6.</list>7.</property>8.9.<!-- 添加listener -->10.<property name="globalTriggerListeners">11.<list>12.<ref local="myTaskTriggerListener"/>13.</list>14.</property>15.</bean>1.2. CronTriggerBean实现了Trigger接口,基于Cron表达式的触发器这种触发器的好处是表达式与linux下的crontab一致,能够满足非常复杂的定时需求,也容易配置Spring配置范例:[xhtml]view plaincopy1.<bean id="notifyTrigger"class="org.springframework.scheduling.quartz.CronTriggerBean">2.<property name="jobDetail"ref="notifyJobDetail"/>3.<property name="cronExpression"value="${notify_trigger_cron_expression}"/>4.</bean>1.3. SimpleTriggerBean该类也实现了Trigger接口,基于配置的定时调度这个触发器的优点在于很容易配置一个简单的定时调度策略Spring配置范例:[xhtml]view plaincopy1.<bean id="simpleReportTrigger"class="org.springframework.scheduling.quartz.SimpleTriggerBean">2.<property name="jobDetail">3.<ref bean="reportJob"/>4.</property>5.<property name="startDelay">6.<value>3600000</value>7.</property>8.<property name="repeatInterval">9.<value>86400000</value>10.</property>11.</bean>1.4. JobDetailBeanJobDetail类的简单扩展,能够包装一个继承自QuartzJobBean的普通Bean,使之成为定时运行的Job缺点是包装的Bean必须继承自一个指定的类,通用性不强,对普通Job的侵入性过强,不推荐使用1.5. MethodInvokingJobDetailFactoryBeanSpring提供的一个不错的JobDetail包装工具,能够包装任何bean,并执行类中指定的任何stati或非static的方法,避免强制要求bean去实现某接口或继承某基础类Spring配置范例:[xhtml]view plaincopy1.<bean id="notifyJobDetail"parent="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">2.<property name="targetObject"ref="notifyServerHandler"/>3.<property name="targetMethod"value="execute"/>4.</bean>1.6. 关于TriggerListener和JobListenerQuartz中提供了类似WebWork的拦截器的功能,系统执行任务前或任务执行完毕后,都会检查是否有对应的Listener需要被执行,这种AOP的思想为我们带来了灵活的业务需求实现方式。
java 定时器用法
Java定时器用法详解一、简介Java定时器(Timer)是Java编程语言中用于实现定时任务的一种工具。
它允许开发者在指定的时间间隔内执行特定的代码块,从而实现定时操作。
本文将详细介绍Java定时器的用法,包括创建定时器、设置任务、启动和停止定时器等内容。
二、创建定时器在Java中,要使用定时器,首先需要导入`java.util.Timer`类。
创建定时器的方法如下:import java.util.Timer;public class MyTimer {public static void main(String[] args) {Timer timer = new Timer();}}三、设置任务定时器的核心功能是执行定时任务,因此需要为定时器设置一个任务。
在Java 中,可以通过创建一个继承自`java.util.TimerTask`的类来实现定时任务。
以下是一个简单的示例:import java.util.TimerTask;class MyTask extends TimerTask {@Overridepublic void run() {System.out.println("定时任务执行");}}四、启动定时器创建好定时器和任务后,接下来需要启动定时器。
可以使用`schedule()`方法来设置定时器的任务和执行间隔。
以下是一个完整的示例:import java.util.Timer;import java.util.TimerTask;class MyTask extends TimerTask {@Overridepublic void run() {System.out.println("定时任务执行");}}public class MyTimer {public static void main(String[] args) {Timer timer = new Timer();MyTask task = new MyTask();timer.schedule(task, 0, 1000); // 立即执行,然后每隔1秒执行一次}}五、停止定时器在某些情况下,可能需要停止定时器的执行。
spring定时器定时任务到时间未执行问题的解决
spring定时器定时任务到时间未执⾏问题的解决⽬录spring定时器定时任务到时间未执⾏应⽤场景原因分析解决⽅式解决修改系统时间后Spring 定时任务不执⾏问题描述起因错误解决问题spring定时器定时任务到时间未执⾏应⽤场景⼀个定时器类中有n个定时任务,有每30秒执⾏⼀次的还有每1分钟执⾏⼀次的,出现问题的定时任务是0点整时执⾏的定时任务到了0点没有执⾏。
原因分析spring定时器任务scheduled-tasks默认配置是单线程串⾏执⾏的,当某个定时任务出现阻塞,或者执⾏时间过长,则线程就会被占⽤,其他定时任务排队执⾏,导致后⾯的定时任务未能准时执⾏。
解决⽅式开启多线程定时任务执⾏/*** 多线程执⾏定时任务*/@Configurablepublic class ScheduleConfig implements SchedulingConfigurer {private static final int FIVE = 5;@Overridepublic void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(FIVE));}}解决修改系统时间后Spring 定时任务不执⾏问题描述Spring 定时任务不执⾏事情起因是这样的,我们有⼀个spring定时任务,每隔半⼩时要执⾏⼀次。
起因由于种种原因,昨晚上这台服务器被关机了,今早【重启服务器】和【启动定时任务服务】。
机器重启后,发现服务器机器系统时间和实际北京时间不⼀致,相差10个⼩时。
于是乎,我使⽤date -s 10:35:35 设置和北京时间保持⼀致。
错误本以为这样,时间已经⼀致了,定时任务应该能正常执⾏了!等了好⼏个⼩时,定时任务依然没有执⾏。
Springboot定时任务Scheduled重复执行操作
Springboot定时任务Scheduled重复执⾏操作今天⽤scheduled写定时任务的时候发现定时任务⼀秒重复执⾏⼀次,⽽我的cron表达式为 * 0/2 * * * * 。
在源码调试的过程中,发现是我的定时任务执⾏过程太短导致的。
于是我另外写了个简单的定时任务@Componentpublic class TestJob {@Scheduled(cron = "* 0/2 * * * *")public void test() {System.out.println("测试开始");System.out.println("测试结束");}}上述任务在启动之后⼀直执⾏。
然后我在任务后⾯加⼊线程睡眠1分钟。
@Componentpublic class TestJob {@Scheduled(cron = "* 0/2 * * * *")public void test() {System.out.println("测试开始");System.out.println("测试结束");try {Thread.sleep(60000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("睡眠结束");}}上述任务执⾏⼀次就没有再执⾏了。
所以我继续深⼊查看源码,发现问题在于CronSequenceGenerator.class的next⽅法。
public Date next(Date date) {Calendar calendar = new GregorianCalendar();calendar.setTimeZone(this.timeZone);calendar.setTime(date);//1.设置下次执⾏时间的毫秒为0,如上次任务执⾏过程不⾜1秒,则calendar的时间会被设置成上次任务的执⾏时间calendar.set(14, 0);long originalTimestamp = calendar.getTimeInMillis();this.doNext(calendar, calendar.get(1));//2.由于有上⾯⼀步,执⾏时间太短,会导致下述条件为trueif(calendar.getTimeInMillis() == originalTimestamp) {//3.calendar在原来的时间上增加1秒calendar.add(13, 1);//CronSequenceGenerator的doNext算法从指定时间开始(包括指定时间)查找符合cron表达式规则下⼀个匹配的时间//注意第⼀个匹配符是*,由于增加了1秒,依然符合cron="* 0/2 * * * *",所以下⼀个执⾏时间就是在原来的基础上增加了⼀秒this.doNext(calendar, calendar.get(1));}return calendar.getTime();}请查看代码中的注释,由于任务执⾏时间太短了,代码会进⼊if语句,并设置执⾏时间在原来的基础上增加⼀秒。
SpringBoot执行定时任务@Scheduled的方法
SpringBoot执⾏定时任务@Scheduled的⽅法在做项⽬时,需要⼀个定时任务来接收数据存⼊数据库,后端再写⼀个接⼝来提供该该数据的最新的那⼀条。
数据保持最新:设计字段sign的值(0,1)来设定是否最新定时任务插⼊数据:⾸先进⾏更新,将所有为1即新数据设置过期,然后插⼊新数据,设置sign为1。
这两个操作是原⼦操作。
通过添加事务来进⾏控制。
Java 定时任务的⼏种实现⽅式基于 java.util.Timer 定时器,实现类似闹钟的定时任务使⽤ Quartz、elastic-job、xxl-job 等开源第三⽅定时任务框架,适合分布式项⽬应⽤使⽤ Spring 提供的⼀个注解: @Schedule,开发简单,使⽤⽐较⽅便,也是本⽂介绍的⼀种⽅式Spring 提供的⼀个注解: @Schedule,开发简单,使⽤⽐较⽅便,也是本⽂介绍的⼀种⽅式Spring ⾃⾝提供了对定时任务的⽀持,本⽂将介绍 Spring Boot 中 @Scheduled 定时器的使⽤。
创建定时任务⾸先,在项⽬启动类上添加@EnableScheduling注解,开启对定时任务的⽀持@SpringBootApplication@EnableSchedulingpublic class ScheduledApplication {public static void main(String[] args) {SpringApplication.run(ScheduledApplication.class, args);}}其中@EnableScheduling注解的作⽤是发现注解@Scheduled的任务并后台执⾏。
其次,编写定时任务类和⽅法,定时任务类通过Spring IOC 加载,使⽤@Component注解,定时⽅法使⽤@Scheduled注解。
@Componentpublic class ScheduledTask {@Scheduled(fixedRate = 3000)public void scheduledTask() {System.out.println("任务执⾏时间:" + LocalDateTime.now());}}fixedRate 是 long 类型,表⽰任务执⾏的间隔毫秒数,以上代码中的定时任务每 3 秒执⾏⼀次。
springboot使用定时器@Scheduled不管用的解决
springboot使⽤定时器@Scheduled不管⽤的解决⽬录使⽤定时器@Scheduled不管⽤多个@Scheduled定时器不执⾏解决⽅法使⽤定时器@Scheduled不管⽤如果是⼀开始就不能⽤就是没写@EnableScheduling注解,如果是⽤着⽤着不管⽤了是因为@Scheduled是单线程,有定时器在⼯作或者没有运⾏完毕,所以造成了线程堵塞所以导致下⼀个定时器不能运⾏增加⼀个⽅法类package com.llt;import org.springframework.boot.autoconfigure.batch.BatchProperties;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.config.ScheduledTaskRegistrar;import ng.reflect.Method;import java.util.concurrent.Executors;@Configurationpublic class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {Method[] methods = BatchProperties.Job.class.getMethods();int defaultPoolSize = 3;int corePoolSize = 0;if (methods != null && methods.length > 0) {for (Method method : methods) {Scheduled annotation = method.getAnnotation(Scheduled.class);if (annotation != null) {corePoolSize++;}}if (defaultPoolSize > corePoolSize)corePoolSize = defaultPoolSize;}taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));}}就好了!多个@Scheduled定时器不执⾏最近项⽬中经常有⽤到@Scheduled注解,在内测时由于数据量⼩(没有进⾏压⼒测)所以每个线程执⾏都很快,但线上后发现部分功能⽆法使⽤,最后定位是部分的定时器没有执⾏,后查阅资料和Springboot源码后ScheduledTaskRegistrar在启动时,如果没有指定线程池的⼤⼩,默认会创建核⼼线程数为1的默认线程池,故⽽当项⽬中出现多个@Scheduled线程时,只能⼀个个的执⾏,从⽽导致个别线程执⾏时间过长(或长期执⾏)时,其他定时器不能按照指定的规则进⾏执⾏。
定时器的用法
定时器的用法定时器确实是一项了不起的发明,使相当多需要人控制时间的工作变得简单了许多。
下面店铺就给大家介绍定时器的用法。
定时器的用法1、调整当前时间使用定时器时,须先将定时器的显示时间调整到当前时间。
按住“时钟”键的同时,分别按“星期”、“小时”和“分钟”键,调整到当前的时间。
(每按一次增加一小时,长按可快速调整。
) 按“时钟”键3秒后,当前时间增加1小时,同时液晶屏显示“夏令时”字样,进入夏令时功能,再按"时钟"键3秒,取消夏令时功能,时间自动减少1小时。
2、设置程序按“设定”键,即可进入定时模式设置,屏幕上显示“1开”。
按“小时”、“分钟”和“星期”,即第一组定时开开始工作的时间。
其中,按“星期”键,可选择不同星期组合模式。
可根据需求,定时器只在设定的星期数中工作。
再按“设定”键,屏幕上显示“1关”,即第一组定时关闭时间,时间设置参考一开设置方法。
依次类推,最多可设置20组开与关。
设置完成后按“时钟”键返回当前时间。
注:1.如果每天不需要设定20组,而其他组已设定,必须按“清除”键,将多余各组的时间程序清除。
2.定时设置完成后,应按“设定”键检查多次定时设定情况是否与实际情况一致。
如有异,请按时间需要进行调整或重新设定。
注:1.如果每天不需要设定20组,而其他组已设定,必须按“清除”键,将多余各组的时间程序清除。
2.定时设置完成后,应按“设定”键检查多次定时设定情况是否与实际情况一致。
如有异,请按时间需要进行调整或重新设定。
如设置的时间程序是跨天的,需要逐一将“开”与“关”时间程序相对应的星期模式对应好。
3、定时器工作模式选择在当前时间状况下,连续按“模式”键,显示屏的左侧将循环显示“自动关”、“开”、“自动开”、“关”四种模式。
根据您的需要进行模式选择。
四种模式释意:“开”:定时器一直有电源输出,没有定时功能;“关”:定时器无电源输出,呈关闭状态;“自动开”:定时器接通电源时有电源输出,之后按设定的程序工作;“自动关”:定时器接通电源时无电源输出,之后按设定的程序工作。
前端开发中的定时任务和定时器使用技巧
前端开发中的定时任务和定时器使用技巧随着互联网的快速发展,前端开发在应用程序中的重要性也日益凸显。
在前端开发中,定时任务和定时器的使用非常常见。
它们可以帮助我们实现自动化的操作,提高用户体验和系统性能。
但是,要正确地使用定时任务和定时器,并充分发挥它们的优势,我们需要掌握一些技巧。
一、了解定时任务与定时器的区别和应用场景在深入研究定时任务和定时器的使用技巧之前,我们首先需要明确它们的区别和应用场景。
定时任务是指在指定的时间执行某个任务。
例如,我们可以设置定时任务在每天凌晨0点执行一次备份数据库的操作,或者定时任务在每隔一定时间刷新页面的内容。
而定时器则是指在指定的时间间隔执行某个任务。
比如,我们可以设置定时器每隔1秒执行一次轮播图片的切换效果,或者定时器每隔5分钟向服务器发送一次数据更新请求。
二、合理选择定时任务和定时器的设置在选择定时任务和定时器的设置时,我们应根据具体的业务需求和用户体验来决定。
对于耗时较长的任务,我们可以使用定时任务进行处理。
通过合理设置定时任务的执行时间,可以避免对用户造成过大的等待时间。
另外,在设置定时任务时,我们还可以考虑巧妙利用多线程技术,提高任务执行效率。
对于需要实时响应的操作,我们可以使用定时器来处理。
通过合理设置定时器的时间间隔,可以让页面在用户操作时及时更新内容。
此外,在设置定时器时,我们还要注意性能消耗的问题,避免不必要的资源浪费。
三、防止定时任务和定时器的冲突和误操作在实际开发中,有时候我们会遇到同时使用定时任务和定时器的情况。
为了避免冲突和误操作,我们需要采取一些措施。
首先,我们要确保定时任务和定时器的运行时间不重叠。
可以通过合理安排执行时间或者加锁的方式实现。
另外,在使用定时器时,如果用户触发了某个操作,我们需要先判断当前是否有正在执行的定时任务,如果有,则先停止定时任务再执行用户操作,以免造成数据错误或界面异常。
其次,我们要避免频繁的定时任务和定时器的触发。
java中spring与Quartz 整合定时任务
现在想要获得在特定时间或者指定时间执行相应功能有两种做法在applicationContext.xml中写入如下Bean<bean id="repeatingTrigger"class="org.springframework.scheduling.timer.ScheduledTimerTask"> <!--启动一秒后执行 --><property name="delay"><value>1000</value></property><!--每隔一小时执行一次 --><property name="period"><value>3600000</value></property><!--注入要监控的javaBean --><property name="timerTask"><ref bean="task" /></property><!--类型是否为fixedRate型,默认为fixedDelay--><property name="fixedRate"><value>true</value></property></bean><bean id="scheduler"class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"><list><ref bean="repeatingTrigger" /></list></property></bean><bean id="task" class="com.css.wam.portlet.SampleTask"><property name="workService"><ref bean="workService" /></property><property name="work"><ref bean="work" /></property></bean>然后写SampleTask类,如下:package com.css.wam.portlet;import java.util.ArrayList;import java.util.Calendar;import java.util.Iterator;import java.util.List;import java.util.TimerTask;import javax.servlet.ServletContext; 字串2import org.apache.jetspeed.security.SecurityException; 字串9 import com.css.wam.service.WorkService; 字串1@SuppressWarnings("unused")class SampleTask extends TimerTask{ 字串2private static final int C_SCHEDULE_HOUR = 23;//设置指定时间private WorkService workService;private List users;private List teams;private WorkPortlet work;public void setWorkService(WorkService workService) {this.workService = workService;} 字串7public void setWork(WorkPortlet work) {this.work = work;} 字串4public SampleTask(){}@SuppressWarnings("unchecked")public void run() {Calendar cal = Calendar.getInstance();try {users = work.getUsers();teams = new ArrayList();for(Iterator it = users.iterator(); it.hasNext();){String teamname = work.getGroupsByUser((String)it.next()); teams.add(teamname);}//查看当前时间与指定是否一致,一致则执行任务if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY) ) 字串6workService.autoWorkOff(users, teams); 字串8} catch (SecurityException e) {e.printStackTrace();}}}使用Quartz定时<bean id="methodInvokingJobDetail"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject"><ref bean="changeService"/></property><property name="targetMethod"><value>changeAll</value></property></bean><bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"><ref bean="methodInvokingJobDetail"/></property><property name="cronExpression"><!--<value>0 0 6,12,20 * * ?</value>--><value>0 0 23 * * ?</value></property></bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><list><ref local="cronTrigger"/></list></property></bean>简单定时<bean id="methodInvokingJobDetail"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject"><ref bean="sgService"/></property><property name="targetMethod"><value>updateNowSgList</value></property></bean><bean id="simpleTrigger"class="org.springframework.scheduling.quartz.SimpleTriggerBean"><property name="jobDetail"><ref bean="methodInvokingJobDetail"/></property><property name="startDelay"><value>10000</value> <!-- 10 s--></property><property name="repeatInterval"><value>1296000000</value> <!-- 1296000000 6 hours--></property></bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><list><ref local="simpleTrigger"/></list></property></bean>一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。
spring定时器的说明
<property name="jobClass" value="com.zb.job.PlanJob"/>
<!-- 注入参数 -->
<property name="jobDataAsMap"&;entry key="planService" value-ref="planService"></entry>
<entry key="name" value="王二"></entry>
</map>
</property>
</bean>
7.注入触发器
第一种: 间隔时间发生事情
<bean id="mytrig" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<!-- 间隔时间 -->
<property name="repeatInterval" value="3000"></property>
</bean>
第二种 : 每天的某个时间发生
<bean id="mytrig" class="org.springframework.scheduling.quartz.CronTriggerBean">
spring quartz定时器的简单配置和使用
</bean>
<!-- 第三步: 定义好调用模式: 如每隔2秒钟调用一次或每天的哪个时间调用一次等 -->
<bean id="printTimerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="applicationContextSchedulerContextKey" value="applicationContext"/>
<property name="triggers">
<list>
<property name="jobDetail" ref="printTimerJob" />
<property name="cronExpression" value="0/2 * * * * ?" />
</bean>
<!-- 启动定时器 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 加载spring的配置文件(一个或者多个) -->
<context-param>
<param-name>contextConfigLocation</param-name>
使用spring的@Scheduled注解执行定时任务,启动项目不输出警告
使⽤spring的@Scheduled注解执⾏定时任务,启动项⽬不输出警告在applicationContext.xml中添加:xmlns:task="/schema/task"xsi:schemaLocation="/schema/task/schema/task/spring-task-4.0.xsd"><task:annotation-driven executor="myExecutor" scheduler="myScheduler"/><task:executor id="myExecutor" pool-size="5"/><task:scheduler id="myScheduler" pool-size="10"/>java代码:@Componentpublic class CleanExpireTokenTask {private Logger logger = LoggerFactory.getLogger(LogTag.BUSINESS);@Scheduled(cron = "0 * * * * ?")public void startUpdateSaleThread(){try{System.out.println("check token expire");}catch(Exception e){logger.error("Make salesReport faild",e);}}}注意:实现类上要加注解@Component定时器的任务⽅法不能有返回值配置及启动报错问题参考⾃2016-11-22⽇安全关闭spring定时任务线程池java代码@Resource(name = "myScheduler")private ThreadPoolTaskScheduler threadPoolTaskScheduler;/*** 等待正在执⾏的定时任务执⾏完毕,不再执⾏新的定时任务,*/public void shutdown(){ threadPoolTaskScheduler.shutdown(); // 等待任务执⾏完毕 while(threadPoolTaskScheduler.getActiveCount() > 0){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }}注:1.根据测试,通过此⽅式创建的定时任务,⽐如每分钟0秒执⾏任务,如果上⼀分钟0秒执⾏的任务还没执⾏完,则这次任务就不会启动。
【spring-boot】springboot整合quartz实现定时任务
【spring-boot】springboot整合quartz实现定时任务在做项⽬时有时候会有定时器任务的功能,⽐如某某时间应该做什么,多少秒应该怎么样之类的。
spring⽀持多种定时任务的实现。
我们来介绍下使⽤spring的定时器和使⽤quartz定时器 1.我们使⽤spring-boot作为基础框架,其理念为零配置⽂件,所有的配置都是基于注解和暴露bean的⽅式。
2.使⽤spring的定时器: spring⾃带⽀持定时器的任务实现。
其可通过简单配置来使⽤到简单的定时任务。
@Component@Configurable@EnableSchedulingpublic class ScheduledTasks{@Scheduled(fixedRate = 1000 * 30)public void reportCurrentTime(){System.out.println ("Scheduling Tasks Examples: The time is now " + dateFormat ().format (new Date ()));}//每1分钟执⾏⼀次@Scheduled(cron = "0 */1 * * * * ")public void reportCurrentByCron(){System.out.println ("Scheduling Tasks Examples By Cron: The time is now " + dateFormat ().format (new Date ()));}private SimpleDateFormat dateFormat(){return new SimpleDateFormat ("HH:mm:ss");}}没了,没错,使⽤spring的定时任务就这么简单,其中有⼏个⽐较重要的注解: @EnableScheduling:标注启动定时任务。
SpringBoot实现定时任务和异步调用
SpringBoot实现定时任务和异步调⽤本⽂实例为⼤家分享了SpringBoot实现定时任务和异步调⽤的具体代码,供⼤家参考,具体内容如下环境:jdk1.8;spring boot2.0.2;Maven3.3摘要说明:定时任务:定时任务是业务场景中经常出现的⼀种情况如:定时发送邮件,短信、定时统计监控数据、定时对账等异步调⽤:⼀个都买流程可能包括下单、发货通知、短信推送、消息推送等,其实除了下单这个主要程序是主程序,其他⼦程序可以同时进⾏且不影响主程序的运⾏,这个时候就可以使⽤异步调⽤来调⽤这些⼦程序;步骤:1.定时任务a.在spring boot主类上使⽤注解@EnableScheduling启动定时任务:package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableScheduling;//启动定时任务@EnableScheduling@SpringBootApplicationpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}b.实现定时任务(使⽤@Component注解来标注组件)/*** @模块名:demo* @包名:ponent* @描述:SchedulingComponent.java* @版本:1.0* @创建⼈:cc* @创建时间:2018年9⽉29⽇上午10:19:37*/package ponent;import java.util.Date;import org.springframework.scheduling.annotation.Scheduled;import ponent;/*** @模块名:demo* @包名:ponent @类名称: SchedulingComponent* @类描述:【类描述】⽤于测试定时任务 @版本:1.0* @创建⼈:cc* @创建时间:2018年9⽉29⽇上午10:19:37*/@Componentpublic class SchedulingComponent {/**** @⽅法名:testScheduling1* @⽅法描述【⽅法功能描述】测试定时任务,没三秒执⾏⼀次* @修改描述【修改描述】* @版本:1.0* @创建⼈:cc* @创建时间:2018年9⽉29⽇上午10:26:20* @修改⼈:cc* @修改时间:2018年9⽉29⽇上午10:26:20*/@Scheduled(fixedRate = 3000)public void testScheduling1() {System.out.println("执⾏时间为"+new Date()+"执⾏testScheduling1");}}@Scheduled注解和之前spring使⽤xml配置定时任务类似:@Scheduled(fixedRate = 5000) :上⼀次开始执⾏时间点之后5秒再执⾏@Scheduled(fixedDelay = 5000) :上⼀次执⾏完毕时间点之后5秒再执⾏@Scheduled(initialDelay=1000, fixedRate=5000) :第⼀次延迟1秒后执⾏,之后按fixedRate的规则每5秒执⾏⼀次@Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则c.上述⽅法写好后启动服务看下控制台结果:2.异步调⽤a.⾸先在spring boot主类上使⽤注解@EnableAsync启动异步调⽤package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;//启动异步调⽤@EnableAsync@SpringBootApplicationpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}b.sping boot异步调⽤很简单,只需使⽤@Async注解标明⽅法(接⼝⽅法)异步package ponent;public interface TaskComponent {void test1() throws Exception;void test2() throws Exception;void test3() throws Exception;}package ponent.impl;import java.util.Random;import org.springframework.scheduling.annotation.Async;import ponent;import ponent.TaskComponent;@Componentpublic class TaskComponentImpl implements TaskComponent {public static Random random = new Random();@Override@Asyncpublic void test1() throws InterruptedException {System.out.println("开始做任务⼀");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("完成任务⼀,耗时:" + (end - start) + "毫秒");}@Override@Asyncpublic void test2() throws InterruptedException {System.out.println("开始做任务⼆");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("完成任务⼆,耗时:" + (end - start) + "毫秒");}@Override@Asyncpublic void test3() throws InterruptedException {System.out.println("开始做任务三");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");}}c.使⽤测试类进⾏测试:package com.example.demo;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;import org.springframework.boot.web.server.LocalServerPort;import org.springframework.test.context.junit4.SpringRunner;import ponent.TaskComponent;@RunWith(SpringRunner.class)// 引⼊SpringBootTest并⽣成随机接⼝@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)public class AsyncTest {// 注⼊随机接⼝@LocalServerPortprivate int port;@Autowiredprivate TaskComponent taskComponent;@Testpublic void testTask() {try {taskComponent.test1();taskComponent.test2();taskComponent.test3();System.out.println("执⾏主线程");// 主线程休眠10秒等待上述异步⽅法执⾏Thread.sleep(10000);}catch (Exception e) {System.out.println(e);}}}执⾏结果如下;可以看出三个异步⽅法互不影响,且不影响主线程的运⾏执⾏主线程开始做任务⼀开始做任务⼆开始做任务三完成任务⼀,耗时:1401毫秒完成任务⼆,耗时:4284毫秒完成任务三,耗时:5068毫秒d.对于这些异步执⾏的调⽤往往会给我们带来思考是不是异步调⽤越多越好,答案当然是否;所以在这⾥引⼊线程池来进⾏异步调⽤控制:在spring boot主类上标注线程池:package com.example.demo;import java.util.concurrent.Executor;import java.util.concurrent.ThreadPoolExecutor;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;//启动定时任务@EnableScheduling@SpringBootApplicationpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}// 启动异步调⽤@EnableAsync@Configurationclass TaskPoolConfig {// 核⼼线程数(setCorePoolSize)10:线程池创建时候初始化的线程数// 最⼤线程数(setMaxPoolSize)20:线程池最⼤的线程数,只有在缓冲队列满了之后才会申请超过核⼼线程数的线程// 缓冲队列(setQueueCapacity)200:⽤来缓冲执⾏任务的队列// 允许线程的空闲时间(setKeepAliveSeconds)60秒:当超过了核⼼线程出之外的线程在空闲时间到达之后会被销毁// 线程池名的前缀(setThreadNamePrefix):设置好了之后可以⽅便我们定位处理任务所在的线程池// 线程池对拒绝任务的处理策略(setRejectedExecutionHandler):这⾥采⽤了CallerRunsPolicy策略,当线程池没有处理能⼒的时候,该策略会直接在 execute// ⽅法的调⽤线程中运⾏被拒绝的任务(setWaitForTasksToCompleteOnShutdown);如果执⾏程序已关闭,则会丢弃该任务// setWaitForTasksToCompleteOnShutdown(true)该⽅法就是这⾥的关键,⽤来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁。
Spring4定时器cronTrigger和simpleTrigger实现方法
Spring4定时器cronTrigger和simpleTrigger实现⽅法spring4定时器 cronTrigger和simpleTrigger实现⽅法Quartz 是个开源的作业调度框架,为在应⽤程序中进⾏作业调度提供了简单却强⼤的机制。
Quartz 允许开发⼈员根据时间间隔(或天)来调度作业。
它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。
整合了 Quartz 的应⽤程序可以重⽤来⾃不同事件的作业,还可以为⼀个事件组合多个作业。
SimpleTrigger 当需要在规定的时间执⾏⼀次或在规定的时间段以⼀定的时间间隔重复触发执⾏Job时,SimpleTrigger就可以满⾜要求;SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔,重复次数属性的值可以为0、正整数、或常量 SimpleTrigger.REPEAT_INDEFINITELY,重复的时间间隔属性值必须为0或长整型的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发执⾏(或⼏乎与Scheduler开始时同时触发执⾏)。
如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建⼀个每间隔10秒钟触发⼀次直到指定的结束时间的 Trigger,⽽⽆需去计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使⽤REPEAT_INDEFINITELY作为重复次数的属性值即可(我们也可以指定⼀个⽐在指定结束时间到达时实际执⾏次数⼤的重复次数)。
CronTrigger ⽀持⽐ SimpleTrigger 更具体的调度,⽽且也不是很复杂。
基于 cron 表达式,CronTrigger ⽀持类似⽇历的重复间隔,⽽不是单⼀的时间间隔。
Cron 表达式包括以下 7 个字段:格式: [秒] [分] [⼩时] [⽇] [⽉] [周] [年]序号说明是否必填允许填写的值允许的通配符1 秒是 0-59 , - * /2 分是 0-59 , - * /3 ⼩时是 0-23 , - * /4 ⽇是 1-31 , - * ? / L W5 ⽉是 1-12 or JAN-DEC , - * /6 周是 1-7 or SUN-SAT , - * ? / L #7 年否 empty 或 1970-2099 , - * /Quartz官⽅⽹站对SimpleTrigger和CronTrigger的简单对⽐:SimpleTrigger is handy if you need 'one-shot' execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time, and have it repeat N times, with a delay of T between executions.当你需要的是⼀次性的调度(仅是安排单独的任务在指定的时间及时执⾏),或者你需要在指定的时间激活某个任务并执⾏N次,设置每次任务执⾏的间隔时间T。
Spring内置定时任务调度@Scheduled使用详解
Spring内置定时任务调度@Scheduled使⽤详解Spring提供了@Scheduled注解⽤于定时任务。
⼀、@Scheduled的基本使⽤启⽤调度⽀持:@EnableScheduling可以将@Scheduled注释与触发器元数据⼀起添加到⽅法中。
例如,以下⽅法每隔5秒调⽤⼀次,并具有固定的延迟,这意味着周期是从前⾯每次调⽤的完成时间开始计算的@Scheduled(fixedDelay=5000)public void doSomething() {// something that should execute periodically}如果需要固定速率执⾏,可以更改批注中指定的属性名。
以下⽅法每5秒调⽤⼀次(在每次调⽤的连续开始时间之间计算)@Scheduled(fixedRate=5000)public void doSomething() {// something that should execute periodically}对于固定延迟和固定速率任务,可以通过指⽰在⾸次执⾏⽅法之前要等待的毫秒数来指定初始延迟@Scheduled(initialDelay=1000, fixedRate=5000)public void doSomething() {// something that should execute periodically}如果简单的周期性调度不够表达,可以提供cron表达式。
例如,以下命令仅在⼯作⽇执⾏:@Scheduled(cron="*/5 * * * * MON-FRI")public void doSomething() {// something that should execute on weekdays only}实现SchedulingConfigurer接⼝,重写configureTasks⽅法:@Schedule注解的⼀个缺点就是其定时时间不能动态更改,它适⽤于具有固定任务周期的任务,若要修改任务执⾏周期,只能⾛“停服务→修改任务执⾏周期→重启服务”这条路。
Spring定时器的时间表达式
Spring定时器的时间表达式定时器的时间表达式:1. 字段允许值允许的特殊字符秒 0-59 , - * /分 0-59 , - * /⼩时 0-23 , - * /⽇期 1-31 , - * ? / L W C⽉份 1-12 或者 JAN-DEC , - * /星期 1-7 或者 SUN-SAT , - * ? / L C #年(可选)留空, 1970-2099 , - * /表达式意义"0 0 12 * * ?" 每天中午12点触发"0 15 10 ? * *" 每天上午10:15触发"0 15 10 * * ?" 每天上午10:15触发"0 15 10 * * ? *" 每天上午10:15触发"0 15 10 * * ? 2005" 2005年的每天上午10:15触发"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发"0 10,44 14 ? 3 WED" 每年三⽉的星期三的下午2:10和2:44触发"0 15 10 ? * MON-FRI" 周⼀⾄周五的上午10:15触发"0 15 10 15 * ?" 每⽉15⽇上午10:15触发"0 15 10 L * ?" 每⽉最后⼀⽇的上午10:15触发"0 15 10 ? * 6L" 每⽉的最后⼀个星期五上午10:15触发"0 15 10 ? * 6L 2002-2005" 2002年⾄2005年的每⽉的最后⼀个星期五上午10:15触发"0 15 10 ? * 6#3" 每⽉的第三个星期五上午10:15触发每天早上6点0 6 * * *每两个⼩时0 */2 * * *晚上11点到早上8点之间每两个⼩时,早上⼋点0 23-7/2,8 * * *每个⽉的4号和每个礼拜的礼拜⼀到礼拜三的早上11点0 11 4 * 1-31⽉1⽇早上4点0 4 1 1 *有些⼦表达式能包含⼀些范围或列表例如:⼦表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT” “*”:字符代表所有可能的值因此,“*”在⼦表达式(⽉)⾥表⽰每个⽉的含义,“*”在⼦表达式(天(星期))表⽰星期的每⼀天“/”:字符⽤来指定数值的增量例如:在⼦表达式(分钟)⾥的“0/15”表⽰从第0分钟开始,每15分钟 ;在⼦表达式(分钟)⾥的“3/20”表⽰从第3分钟开始,每20分钟(它和“3,23,43”)的含义⼀样“?”:字符仅被⽤于天(⽉)和天(星期)两个⼦表达式,表⽰不指定值当2个⼦表达式其中之⼀被指定了值以后,为了避免冲突,需要将另⼀个⼦表达式的值设为“?” “L”:字符仅被⽤于天(⽉)和天(星期)两个⼦表达式,它是单词“last”的缩写但是它在两个⼦表达式⾥的含义是不同的。
spring自带的定时任务功能基于注解和xml配置
spring自带的定时任务功能基于注解和xml配置版权声明:本文为博主原创文章,未经博主允许不得转载。
1、spring的配置文件[html] view plain copy <beans xmlns="/schema/beans" xmlns:xsi="/2001/XMLSchema-instance" xmlns:p="/schema/p" xmlns:task="/schema/task" xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop" xsi:schemaLocation="/schema/ beans/schema/beans/spring-beans-3.0.xsd /schema/tx /schema/tx/spring-tx-3.0.xsd /schema/jee/schema/jee/spring-jee-3.0.xsd /schema/context/schema/context/spring-context -3.0.xsd /schema/aop /schema/aop/spring-aop-3.0.xsd /schema/task /schema/task/spring-task-3.0.xs d"> <task:annotation-driven /> <!-- 定时器开关--> <bean id="myTaskXml"class="com.spring.task.MyTaskXml"></bean><task:scheduled-tasks> <!--这里表示的是每隔五秒执行一次--><task:scheduled ref="myTaskXml" method="show"cron="*/5 * * * * ?" /> <task:scheduledref="myTaskXml" method="print" cron="*/10 * * * * ?"/> </task:scheduled-tasks> <!-- 自动扫描的包名--> <context:component-scanbase-package="com.spring.task" /> </beans>2、基于xml的定时器任务[java] view plain copy package com.spring.task; /** * 基于xml的定时器* @author hj */ public class MyTaskXml { public void show(){ System.out.println("XMl:is show run"); } public voidprint(){ System.out.println("XMl:printrun"); } } 3、基于注解的定时器任务[java] view plain copy package com.spring.task; importorg.springframework.scheduling.annotation.Scheduled; importponent; /** * 基于注解的定时器* @author hj */ @Component public class MyTaskAnnotation { /** * 定时计算。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
定时执行任务,这是项目中常用的东西,今天我们来做一个使用Spring定时器进行任务定制的小例子,仅供学习!
1首先要增加相应的JAR。
因为这是一个小例子,使用的JAR包不是很多,用到了spring.jar,
quartz-all-1.6.5.jar,quartz-1.5.2.jar,commons-logging.jar,
log4j-1.2.14.jar!不用关心版本,从你下载到的Spring中找即可。
定义web.xml配置文件
要在配置文件中定义Spring和Log4j的使用。
具体看工程即可。
重点关注的是如果你做例子时使用了web-app_2_5.xsd,那么在部分服务器上是跑不起
来的。
Xml代码
1<?xml version="1.0" encoding="UTF-8"?>
1<!-- 如果定义的是web-app_2_5.xsd,那么在部分服务器上是跑不通过的
-->
1<web-app version="2.4" xmlns="/xml/ns/j2ee"
1xmlns:xsi="/2001/XMLSchema-instance"
1xsi:schemaLocation="/xml/ns/j2ee
1/xml/ns/j2ee/web-app_2_4.xsd">
1<!-- 系统默认首页面-->
1<welcome-file-list>
1<welcome-file>index.jsp</welcome-file>
1</welcome-file-list>
1
1<!-- 定义Spring配置文件的加载路径-->
1<context-param>
1<param-name>contextConfigLocation</param-name>
1<param-value>/WEB-INF/spring.xml</param-value>
1</context-param>
1<!-- 定义Log4j日志配置文件-->
1<context-param>
1<param-name>log4jConfigLocation</param-name>
1<param-value>/WEB-INF/classes/log4j.properties</param-value> 1</context-param>
1
1<!-- 定义日志监听-->
1<listener>
1<listener-class>
1org.springframework.web.util.Log4jConfigListener
1</listener-class>
1</listener>
1<!-- 定义Spring监听-->
1<listener>
1<listener-class>
1org.springframework.web.context.ContextLoaderListener
1</listener-class>
1</listener>
1</web-app>
定义Spring配置文件
这个文件的位置你可以自己定义,我放到了web-inf下面。
里面需要定义四个内容,具体看注释。
重点是时间间隔的配置,这个你可以网上查一下,或看
readme文件。
Xml代码
1<?xml version="1.0" encoding="UTF-8"?>
1<beans xmlns="/schema/beans"
1xmlns:xsi="/2001/XMLSchema-instance"
1xsi:schemaLocation="/schema/beans
1/schema/beans/spring-beans-2.0.xsd">
1<!-- 每个定义的任务都要在这里进行引用才能运行-->
1<bean
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
1<property name="triggers">
1<list>
1<ref local="BusinessTestTrigger" />
1</list>
1</property>
1</bean>
1<!-- 定义我们要运行的类,可以使用注入定制一些参数-->
1<bean id="BusinessTestTime" class="com.test.Test">
1<property name="para" value="Spring定时器测试V1" />
1</bean>
1<!-- 引用,配置要运行的方法-->
1<bean id="BusinessTestDetail"
1class="org.springframework.scheduling.quartz.MethodInvokingJobDetailF actoryBean">
1<property name="targetObject">
1<ref bean="BusinessTestTime" />
1</property>
1<property name="concurrent" value="false" />
1<property name="targetMethod" value="run" />
1</bean>
1<!-- 引用,定制调用间隔,具体时间配置的正则,请阅读readme.txt --> 1<bean id="BusinessTestTrigger"
1class="org.springframework.scheduling.quartz.CronTriggerBean">
1<property name="jobDetail">
1<ref bean="BusinessTestDetail" />
1</property>
1<property name="cronExpression">
1<value>0/5 * * * * ?</value>
1</property>
1</bean>
1</beans>
执行的代码
这个代码就是一个普通的代码,里面定义一个要执行的方法就可以了,方法
名称自己定义并在Spring配置文件中配置即可。
Java代码
1package com.test;
1import java.text.SimpleDateFormat;
1import java.util.Date;
1/**
1* 执行类
1*/
1public class Test {
1// 执行参数
1private String para ;
1// 执行方法
1public void run() {
1// 定义输出的格式化日期,以便于区分调用
1SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd
HH:mm:ss");
1System.out.println("the para is : " + para + " ! Time is :" +
format.format(new Date()));
1}
1public String getPara() {
1return para;
1}
1public void setPara(String para) {
1this.para = para;
1}
1}
备注:工程直接使用工具导入即可查看代码,将工程部署即可在控制台看到效果。