背景:
项目中遇到这样一个问题,一个接口涉及到复杂运算(日环比,周同比,数据量大),前端查询相关报表统计信息时候,耗时两秒左右;现在考虑用map缓存查询结果;一种方法是:实现接口 CommandLineRunner,重写run方法,利用ScheduledExecutorService 线程池定时查询结果并保存在sevice中的map中,接口查询时候先走map;大致过程如下:
@Component
public class MyCommandLineRunner implements CommandLineRunner {
private StatisticsTasker statisticsTasker;
private static ScheduledExecutorService timer = newScheduledThreadPool(2);
@Override
public void run(String... args) throws Exception {
this.statisticsTasker = new StatisticsTasker(ApplicationContextHelper.getContext().getBean(UserServiceImpl.class));
timer.scheduleAtFixedRate(statisticsTasker,1000,2000, TimeUnit.MILLISECONDS);
}
}
@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StatisticsTasker implements Runnable {
private UserServiceImpl userServiceImpl;
@Override
public void run() {
WalletStatisticsDTO walletStatistics = userServiceImpl.walletStatistics(true);
userServiceImpl.statistics.put("walletStatistics",walletStatistics);
}
}
ApplicationContextHelper是一个工具类:
/**
* spring工厂调用辅助类
* @author flyleft
*/
public class ApplicationContextHelper implements ApplicationContextAware {
private static DefaultListableBeanFactory springFactory;
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
if (applicationContext instanceof AbstractRefreshableApplicationContext) {
AbstractRefreshableApplicationContext springContext =
(AbstractRefreshableApplicationContext) applicationContext;
springFactory = (DefaultListableBeanFactory) springContext.getBeanFactory();
} else if (applicationContext instanceof GenericApplicationContext) {
GenericApplicationContext springContext = (GenericApplicationContext) applicationContext;
springFactory = springContext.getDefaultListableBeanFactory();
}
}
public static DefaultListableBeanFactory getSpringFactory() {
return springFactory;
}
public static ApplicationContext getContext() {
return context;
}
}
这样,应用启动之后,定时任务会定时调用service的statistics接口,并将结果放入map当中;页面查询直接从map当中取数据;
二:考虑从程序入口,开启一个线程来执行初始化的逻辑:
public class SpringDemolication {
public static void main(String[] args)
{
SpringApplication.run(SpringDemolication.class, args);
triggerInit();
}
private static void triggeInit() {
new Thread(() -> InitExecutor.doInit()).start();
}
}
@Slf4j
public final class InitExecutor {
private static AtomicBoolean initialized = new AtomicBoolean(false);
private static ScheduledExecutorService timer = newScheduledThreadPool(2);
public static void doInit() {
if (initialized.compareAndSet(false, true)) {
try {
timer.scheduleAtFixedRate(new StatisticsTasker(ApplicationContextHelper.getContext().getBean(UserServiceImpl.class)), 1000, 2000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.info("[InitExecutor] WARN: Initialization failed", e);
e.printStackTrace();
}
}
}
private InitExecutor() {
}
这样也可以执行初始化线程池,执行定时任务
转载:https://blog.csdn.net/yedongfeng_1314/article/details/101701914
查看评论