springboot 在程序入口初始化资源事例

背景:

项目中遇到这样一个问题,一个接口涉及到复杂运算(日环比,周同比,数据量大),前端查询相关报表统计信息时候,耗时两秒左右;现在考虑用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() {
    }

这样也可以执行初始化线程池,执行定时任务

你可能感兴趣的:(springboot 在程序入口初始化资源事例)