spring的内容比较多,常规的知识必须进行系统化的学习,但是一些边缘的技术点,在实际工作中也是非常适用的;下面一一介绍和实践一次。
场景:下发任务跟执行任务分开。
场景 | 常规做法 | 改进做法 |
---|---|---|
计算每天的统计数据,比如日新增,日活跃,日留存等 | 实时计算,计算和获取结果在同一个线程里完成 | 分两个部分:1.触发计算;2.异步完成计算; |
package com.springbootpractice.demo.spring.other.config; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 说明:自定义异步线程池和异常处理 * @author carter * 创建时间: 2020年01月13日 10:12 上午 **/ @EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { /** * @return 线程池 */ @Override public Executor getAsyncExecutor() { return new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000), new ThreadFactoryBuilder().setDaemon(true).setNameFormat("demo_spring_other_%s").build(), new ThreadPoolExecutor.DiscardPolicy() ); } /** * 可以结合监控系统,监控该异常,进行告警 * @return 异常处理 */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new SimpleAsyncUncaughtExceptionHandler(); } }
package com.springbootpractice.demo.spring.other.service; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.util.concurrent.TimeUnit; /** * 说明:统计数据计算业务代码 * @author carter * 创建时间: 2020年01月13日 10:27 上午 **/ @Service @Slf4j public class AsyncSummaryDataService { @Async public void calculateDayNewData(LocalDate day) { try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } log.info("calculateDayNewData 执行线程:{}", Thread.currentThread().getName()); } @Async public void calculateDayLeftData(LocalDate day) { try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } log.info("calculateDayLeftData 执行线程:{}", Thread.currentThread().getName()); } @Async public void calculateDayActiveData(LocalDate day) { try { TimeUnit.SECONDS.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } log.info("calculateDayActiveData 执行线程:{}", Thread.currentThread().getName()); } }
@Autowired private AsyncSummaryDataService asyncSummaryDataService; @Test void asyncTest() { asyncSummaryDataService.calculateDayActiveData(LocalDate.now()); asyncSummaryDataService.calculateDayLeftData(LocalDate.now()); asyncSummaryDataService.calculateDayNewData(LocalDate.now()); }
2020-01-13 10:38:02.084 INFO 35059 --- [_spring_other_1] c.s.d.s.o.s.AsyncSummaryDataService : calculateDayLeftData 执行线程:demo_spring_other_1 2020-01-13 10:38:12.085 INFO 35059 --- [_spring_other_0] c.s.d.s.o.s.AsyncSummaryDataService : calculateDayActiveData 执行线程:demo_spring_other_0 2020-01-13 10:38:12.092 INFO 35059 --- [_spring_other_1] c.s.d.s.o.s.AsyncSummaryDataService : calculateDayNewData 执行线程:demo_spring_other_1 2020-01-13 10:38:12.108 INFO 35059 --- [ main] c.s.d.s.o.service.SummaryDataService : calculateDayActiveData 执行线程:main 2020-01-13 10:38:32.114 INFO 35059 --- [ main] c.s.d.s.o.service.SummaryDataService : calculateDayLeftData 执行线程:main 2020-01-13 10:38:42.117 INFO 35059 --- [ main] c.s.d.s.o.service.SummaryDataService : calculateDayNewData 执行线程:main
B端应用,可能需要一些定时任务,比如月末报表。在spring中启用定时任务非常简单,步骤如下:
@Scheduled注解的配置内容
配置项 | 说明 |
---|---|
cron | cron表达式 |
zone | 时区 |
fixedDelay,fixedDelayString | 固定延迟时间,两个任务之间的执行延迟;_milliseconds_ |
fixedRate,fixedRateString |
固定频率,两个任务之间固定的执行间隔 milliseconds |
initialDelay,initialDelayString |
初始化延迟,springIOC初始化完毕之后多少延迟之后开始执行首次任务的延迟 milliseconds |
cron表达式不说了,可以直接使用工具生成: http://cron.qqe2.com/ 推荐一个;
实例: 0 0 0 ? 每天0点开始执行;
实例代码:
package com.springbootpractice.demo.spring.other.service; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Schedules; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * 说明:TODO * @author carter * 创建时间: 2020年01月13日 11:14 上午 **/ @Service @Slf4j public class ScheduleTaskService { @Schedules({ @Scheduled(initialDelay = 5 * 1000, fixedRate = 10 * 1000) }) public void generateMonthReport() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } log.info("执行月报表计算"); } }
代码点我获取!
原创不易,转载请注明出处,欢迎沟通交流。