(3)springboot restful service - PostConstruct 启动后执行的任务

123 阅读1分钟
  1. 有些任务需要服务启动后立即执行,比如,加载一些数据到内存。可以通过 jakarta.annotation.PostConstruct 注解实现。

建一个 PostConstructService , 在某个方法上加上 注解 PostConstruct

@Service
public class PostConstructService {
    Logger logger = LoggerFactory.getLogger(getClass());

    @PostConstruct
    public void taskAfterStartup() {
        logger.info("run task after startup");
    }

}

启动服务 mvn clean spring-boot:run , 可以看到服务启动后在终端打印出 log , "run task after startup"

postconstruct.png

注意: 这里 log 是由主线程 main 打出的,如果执行任务时间太长,会影响服务启动。 可以使用异步任务,来执行服务启动后的一些初始化操作。

  1. 在 SpringBoot 的启动类, 加上注解 org.springframework.scheduling.annotation.EnableAsync , 支持异步任务。
@EnableAsync
@SpringBootApplication
public class MarsApplication {
    ...
}

配置异步任务的 thread pool , 建一个 ThreadPoolConfig 配置类

@Configuration
public class ThreadPoolConfig {

    @Value("${spring.application.name:}")
    String name;

    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        String namePrefix = String.format("%s_task_", name);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(8);
        executor.setThreadNamePrefix(namePrefix);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setKeepAliveSeconds(60);
        executor.initialize();
        return executor;
    }
}

在 PostConstructService 中定义一个 asyncTask() 任务, 服务启动后执行异步任务 asyncTask() 不会影响服务启动时间。

@Service
public class PostConstructService {
    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    ThreadPoolTaskExecutor executor;

    @PostConstruct
    public void taskAfterStartup() {
        logger.info("run task after startup");
        asyncTask();
    }

    public void asyncTask() {
        FutureTask<String> task = new FutureTask<>(
                () -> {
                    logger.info("it's a async task");
                    return "done";
                }
        );

        executor.execute(task);
    }

}

async_task.png

可以看到 log "it's a async task" 是由线程 mars_task_1 执行的。

  1. 在服务中执行定时任务 (有些类似 cron job) 。

首先配置定时任务的线程池,在 ThreadPoolConfig 中

@Configuration
public class ThreadPoolConfig {
...
     @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        String namePrefix = String.format("%s_scheduler_", name);
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix(namePrefix);
        scheduler.setPoolSize(5);
        scheduler.initialize();
        return scheduler;
    }
}

其次, 在启动类中添加注解 org.springframework.scheduling.annotation.EnableScheduling

@EnableScheduling
@EnableAsync
@SpringBootApplication
public class MarsApplication {

	public static void main(String[] args) {
		SpringApplication.run(MarsApplication.class, args);
	}

}

然后, 建一个 ScheduleTaskService

// 使用注解 @Component

@Component
public class ScheduleTaskService {
    Logger logger = LoggerFactory.getLogger(getClass());

    // 每 10 打印一次 log
    @Scheduled(cron = "*/10 * * * * ?")
    private void schedulePrintLog() {
        long current = System.currentTimeMillis();
        logger.info("scheduling print log, current [{}]", current);
    }
}

schedule_task.png

本节的代码 gitee.com/yren/mars/t…

语雀上的副本 www.yuque.com/u2177997/sr…