定时任务:有时候我们需要做定时的一些操作,比如统计信息,定时发送邮件等
在springboot中如何进行整合和使用呢?
有哪些方式可以实现定时任务呢?
java自带的java.util.timer:
优点:java自带,无需导包
缺点:配置复杂,时间延后等问题
quartz框架:
优点:配置简单,使用方便
缺点:需要导包
@enableschedule:
优点:springboot自带,高兼容,无需导包
使用:
在启动类加入@enablescheduling注解
package org.dreamtech.demo; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.scheduling.annotation.enablescheduling; @springbootapplication @enablescheduling public class demoapplication { public static void main(string[] args) { springapplication.run(demoapplication.class, args); } }
定义task:
package org.dreamtech.demo.task; import java.util.date; import org.springframework.scheduling.annotation.scheduled; import org.springframework.stereotype.component; @component public class testtask { @scheduled(fixedrate = 2000) public void test() { system.out.println("[ " + "当前时间 : " + new date() + " ]"); } }
效果:控制台每过两秒打印一次当前时间
[ 当前时间 : fri may 10 14:01:42 cst 2019 ] [ 当前时间 : fri may 10 14:01:44 cst 2019 ] [ 当前时间 : fri may 10 14:01:46 cst 2019 ] [ 当前时间 : fri may 10 14:01:48 cst 2019 ] [ 当前时间 : fri may 10 14:01:50 cst 2019 ] [ 当前时间 : fri may 10 14:01:52 cst 2019 ] [ 当前时间 : fri may 10 14:01:54 cst 2019 ]
使用cron表达式:
每两秒执行一次的另一种表达方式:
@scheduled(cron = "*/2 * * * * *")
关于cron表达式的百度即可,一堆介绍,我就不多写了
异步任务:适用于发送短信、邮件、处理log等问题
为什么需要异步任务?
比如电商网站用户下单,要做的事情有这几样:库存查询、用户校验、余额校验等
springboot使用异步任务:@enableasync注解
基本实现:
启动类加入@enableasync注解
package org.dreamtech.demo; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.scheduling.annotation.enableasync; @springbootapplication @enableasync public class demoapplication { public static void main(string[] args) { springapplication.run(demoapplication.class, args); } }
定义任务类:这里模拟耗时的操作
package org.dreamtech.demo.task; import org.springframework.scheduling.annotation.async; import org.springframework.stereotype.component; @component @async public class asynctask { public void test1() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(1000); long end = system.currenttimemillis(); system.out.println("[ " + "任务1耗时 : " + (end - begin) + " ]"); } public void test2() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(2000); long end = system.currenttimemillis(); system.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]"); } public void test3() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(3000); long end = system.currenttimemillis(); system.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]"); } }
controller层做测试:
package org.dreamtech.demo.controller; import org.dreamtech.demo.task.asynctask; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller public class testcontroller { @autowired private asynctask task; @getmapping("/test") private object test() { long begin = system.currenttimemillis(); try { task.test1(); task.test2(); task.test3(); } catch (exception e) { e.printstacktrace(); } long end = system.currenttimemillis(); system.out.println("[ " + "controller耗时 : " + (end - begin) + " ]"); return "test"; } }
访问localhost:8080/test打印如下:
[ controller耗时 : 4 ] [ 任务1耗时 : 1000 ] [ 任务2耗时 : 2000 ] [ 任务2耗时 : 3000 ]
结论:异步任务的执行类似多线程,可以用来做一些耗时操作
有时候需要某个任务确定执行完毕才能继续其他操作
如何获取任务的执行结果呢?
package org.dreamtech.demo.task; import java.util.concurrent.future; import org.springframework.scheduling.annotation.async; import org.springframework.scheduling.annotation.asyncresult; import org.springframework.stereotype.component; @component @async public class asynctask { public future<string> test1() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(1000); long end = system.currenttimemillis(); system.out.println("[ " + "任务1耗时 : " + (end - begin) + " ]"); return new asyncresult<string>("任务1"); } public future<string> test2() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(2000); long end = system.currenttimemillis(); system.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]"); return new asyncresult<string>("任务2"); } public future<string> test3() throws interruptedexception { long begin = system.currenttimemillis(); thread.sleep(3000); long end = system.currenttimemillis(); system.out.println("[ " + "任务3耗时 : " + (end - begin) + " ]"); return new asyncresult<string>("任务3"); } }
controller:
package org.dreamtech.demo.controller; import java.util.concurrent.future; import org.dreamtech.demo.task.asynctask; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller public class testcontroller { @autowired private asynctask task; @getmapping("/test") private object test() { long begin = system.currenttimemillis(); try { future<string> task1result = task.test1(); future<string> task2result = task.test2(); future<string> task3result = task.test3(); while (true) { if (task1result.isdone() && task2result.isdone() && task3result.isdone()) { break; } } } catch (exception e) { e.printstacktrace(); } long end = system.currenttimemillis(); system.out.println("[ " + "controller耗时 : " + (end - begin) + " ]"); return "test"; } }
访问localhost:8080/test
等待3秒之后,打印如下:
[ 任务1耗时 : 1001 ] [ 任务2耗时 : 2001 ] [ 任务3耗时 : 3001 ] [ controller耗时 : 3007 ]
只有三个任务都完成,controller层代码才会执行完毕
总结:异步任务大大地提高了开发的效率
顺便来记录logback的使用:
logback:一款优秀的日志框架
springboot的starter默认日志框架:logback,默认级别:info
如果我们想以debug方式启动:java -jar springboot.jar --debug
配置文件:官方推荐名称logback-spring.xml
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appender name="consoleapp" class="ch.qos.logback.core.consoleappender"> <layout class="ch.qos.logback.classic.patternlayout"> <pattern> %date{yyyy-mm-dd hh:mm:ss.sss} %-5level[%thread]%logger{56}.%method:%l -%msg%n </pattern> </layout> </appender> <appender name="fileinfoapp" class="ch.qos.logback.core.rolling.rollingfileappender"> <filter class="ch.qos.logback.classic.filter.levelfilter"> <level>error</level> <onmatch>deny</onmatch> <onmismatch>accept</onmismatch> </filter> <encoder> <pattern> %date{yyyy-mm-dd hh:mm:ss.sss} %-5level[%thread]%logger{56}.%method:%l -%msg%n </pattern> </encoder> <!-- 滚动策略 --> <rollingpolicy class="ch.qos.logback.core.rolling.timebasedrollingpolicy"> <!-- 路径 --> <filenamepattern>app_log/log/app.info.%d.log</filenamepattern> </rollingpolicy> </appender> <appender name="fileerrorapp" class="ch.qos.logback.core.rolling.rollingfileappender"> <filter class="ch.qos.logback.classic.filter.thresholdfilter"> <level>error</level> </filter> <encoder> <pattern> %date{yyyy-mm-dd hh:mm:ss.sss} %-5level[%thread]%logger{56}.%method:%l -%msg%n </pattern> </encoder> <!-- 设置滚动策略 --> <rollingpolicy class="ch.qos.logback.core.rolling.timebasedrollingpolicy"> <!-- 路径 --> <filenamepattern>app_log/log/app.err.%d.log</filenamepattern> <!-- 控制保留的归档文件的最大数量,超出数量就删除旧文件,假设设置每个月滚动, 且<maxhistory> 是1,则只保存最近1个月的文件,删除之前的旧文件 --> <maxhistory>1</maxhistory> </rollingpolicy> </appender> <root level="info"> <appender-ref ref="consoleapp" /> <appender-ref ref="fileinfoapp" /> <appender-ref ref="fileerrorapp" /> </root> </configuration>
使用和测试:
package org.dreamtech.demo.controller; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller public class testcontroller { private logger logger = loggerfactory.getlogger(this.getclass()); @getmapping("/log") private object log() { logger.debug("test"); logger.info("test"); logger.warn("test"); logger.error("test"); return "log"; } }
访问localhost:8080/log
会在项目目录生成一个新目录app_log
存在两个文件:一个用来存放error级别信息,一个存放info级别和warn级别
2019-05-11 12:53:53.668 error[http-nio-8080-exec-1]org.dreamtech.demo.controller.testcontroller.log:18 -test
2019-05-11 12:53:36.264 info [main]org.dreamtech.demo.demoapplication.logstarting:50 -starting demoapplication on desktop-59o94td with pid 14180 (d:\project\sts_project\demo\target\classes started by 20235 in d:\project\sts_project\demo) 2019-05-11 12:53:36.266 info [main]org.dreamtech.demo.demoapplication.logstartupprofileinfo:675 -no active profile set, falling back to default profiles: default 2019-05-11 12:53:37.019 info [main]o.s.boot.web.embedded.tomcat.tomcatwebserver.initialize:90 -tomcat initialized with port(s): 8080 (http) 2019-05-11 12:53:37.031 info [main]org.apache.coyote.http11.http11nioprotocol.log:173 -initializing protocolhandler ["http-nio-8080"] 2019-05-11 12:53:37.039 info [main]org.apache.catalina.core.standardservice.log:173 -starting service [tomcat] 2019-05-11 12:53:37.041 info [main]org.apache.catalina.core.standardengine.log:173 -starting servlet engine: [apache tomcat/9.0.17] 2019-05-11 12:53:37.122 info [main]o.a.catalina.core.containerbase.[tomcat].[localhost].[/].log:173 -initializing spring embedded webapplicationcontext 2019-05-11 12:53:37.122 info [main]org.springframework.web.context.contextloader.preparewebapplicationcontext:296 -root webapplicationcontext: initialization completed in 824 ms 2019-05-11 12:53:37.289 info [main]o.s.scheduling.concurrent.threadpooltaskexecutor.initialize:171 -initializing executorservice 'applicationtaskexecutor' 2019-05-11 12:53:37.413 info [main]org.apache.coyote.http11.http11nioprotocol.log:173 -starting protocolhandler ["http-nio-8080"] 2019-05-11 12:53:37.447 info [main]o.s.boot.web.embedded.tomcat.tomcatwebserver.start:204 -tomcat started on port(s): 8080 (http) with context path '' 2019-05-11 12:53:37.450 info [main]org.dreamtech.demo.demoapplication.logstarted:59 -started demoapplication in 1.528 seconds (jvm running for 2.39) 2019-05-11 12:53:53.641 info [http-nio-8080-exec-1]o.a.catalina.core.containerbase.[tomcat].[localhost].[/].log:173 -initializing spring dispatcherservlet 'dispatcherservlet' 2019-05-11 12:53:53.642 info [http-nio-8080-exec-1]org.springframework.web.servlet.dispatcherservlet.initservletbean:524 -initializing servlet 'dispatcherservlet' 2019-05-11 12:53:53.650 info [http-nio-8080-exec-1]org.springframework.web.servlet.dispatcherservlet.initservletbean:546 -completed initialization in 8 ms 2019-05-11 12:53:53.668 info [http-nio-8080-exec-1]org.dreamtech.demo.controller.testcontroller.log:16 -test 2019-05-11 12:53:53.668 warn [http-nio-8080-exec-1]org.dreamtech.demo.controller.testcontroller.log:17 -test 2019-05-11 12:54:23.513 info [rmi tcp connection(2)-127.0.0.1]o.s.b.a.springapplicationadminmxbeanregistrar$springapplicationadmin.shutdown:163 -application shutdown requested. 2019-05-11 12:54:23.515 info [rmi tcp connection(2)-127.0.0.1]o.s.scheduling.concurrent.threadpooltaskexecutor.shutdown:208 -shutting down executorservice 'applicationtaskexecutor'
如对本文有疑问, 点击进行留言回复!!
[JVM学习之路]一、初识JVM,了解其结构、模型及生命周期
【JAVA并发编程】LinkedBlockingQueue原理
网友评论