Several ways of initializing operation when SpringBoot project starts

Posted by tim_perrett on Sat, 20 Nov 2021 14:51:27 +0100

preface
Usually, in our project development, we often encounter the situation that we need to automatically execute some business code as soon as the service is started. For example, cache the configuration information or data dictionary in the database to redis, or open some configured scheduled tasks when the service is started. There are actually many methods for spring mvc or spring boot to execute some code when the project starts. Let me introduce the three methods I have used.


1. @ PostConstruct annotation

Starting from the Java EE5 specification, two annotations affecting the Servlet life cycle, @ PostConstruct and @ PreDestroy, have been added to the Servlet. These two annotations are used to modify a non static void () method@ PostConstruct will be executed after the constructor of the class is executed and before the init() method is executed. (@ PreDestroy annotated method will be executed after the destruction () method of this class is executed.)
Usage example: after the Spring container is loaded, start the scheduled task to read the database configuration. Here, I use @ PostConstruct to specify the method to be started.
 

@Component // Note that there must be
public class StartAllJobInit {
    protected Logger logger = LoggerFactory.getLogger(getClass().getName());
    @Autowired
    JobInfoService jobInfoService;
 
    @Autowired
    JobTaskUtil jobTaskUtil;
 
    @PostConstruct // Execute after constructor
    public void init(){
        System.out.println("Execute after container startup");
        startJob();
    }
 
    public void startJob() {
        List<JobInfoBO> list = jobInfoService.findList();
        for (JobInfoBO jobinfo :list) {
            try {
                if("0".equals(jobinfo.getStartWithrun())){
                    logger.info("task{}Auto start is not set.", jobinfo.getJobName());
                    jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STOP);
                }else{
                    logger.info("task{}Auto start is set.", jobinfo.getJobName());
                    jobTaskUtil.addOrUpdateJob(jobinfo);
                    jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STARTING);
                }
            } catch (SchedulerException e) {
                logger.error("Error executing scheduled task, task name {} ", jobinfo.getJobName());
            }
        }
    }
}

2. Implement the @ CommandLineRunner interface and override the run() method

After the project is started, SpringBoot will traverse all entity classes that implement CommandLineRunner and execute the run method. Multiple implementation classes can coexist and execute according to the order annotation.
It also executes scheduled tasks at startup. Using this method, I write as follows:
 

@Component // Note that there must be
//@Order(2) if multiple classes need to be started, the value in the order annotation is the starting order
public class StartAllJobInit implements CommandLineRunner {
    protected Logger logger = LoggerFactory.getLogger(getClass().getName());
    @Autowired
    JobInfoService jobInfoService;
 
    @Autowired
    JobTaskUtil jobTaskUtil;
 
    @Override
    public void run(String... args) {
        List<JobInfoBO> list = jobInfoService.findList();
        for (JobInfoBO jobinfo :list) {
            try {
                if("0".equals(jobinfo.getStartWithrun())){
                    logger.info("task{}Auto start is not set.", jobinfo.getJobName());
                    jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STOP);
                }else{
                    logger.info("task{}Auto start is set.", jobinfo.getJobName());
                    jobTaskUtil.addOrUpdateJob(jobinfo);
                    jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STARTING);
                }
            } catch (SchedulerException e) {
                logger.error("Error executing scheduled task, task name {} ", jobinfo.getJobName());
            }
        }
    }
}

3. Implement the @ ApplicationRunner interface and override the run() method

The run method parameter is ApplicationArguments. After parsing the encapsulated args parameter, you can get both the original command line parameters and the parsed parameters through this object. The value in @ Order specifies the execution Order, and the smaller value is executed first. The default value is Integer.MAX_VALUE
 

import java.util.Arrays;
import java.util.Set;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("====================MyApplicationRunner================");
        System.out.println("order Value: 1");
        System.out.println("Original parameters:"+Arrays.asList(args.getSourceArgs()));
        Set<String> keys = args.getOptionNames();
        for (String key : keys) {
            System.out.println("Parsed key: ["+key+"]  value: "+args.getOptionValues(key));
        }
        System.out.println("nothing OptionName Parameters: "+args.getNonOptionArgs());
        System.out.println("=======================================================");
    }

4. Implement the org.springframework.beans.factory.InitializingBean interface and override the afterpropertieset () method  

The InitializingBean interface contains only one method, afterpropertieset(), which will be called during initialization for all classes that inherit the InitializingBean interface;
The usage method is divided into three steps: 1. Managed by spring         2. Implement the InitializingBean interface         3. Override the afterpropertieset method

@Component
public class InitializationBeanTest implements InitializingBean{
    private static final Logger LOG = LoggerFactory.getLogger(InitializationBeanTest.class);
 
    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info("InitializingBean Here we go...");
        //Initialization operation
    }
}

5. Use ContextRefreshedEvent event (upper and lower file refresh event)

ContextRefreshedEvent is an implementation of Spring's ApplicationContextEvent. This event will be triggered after Spring container initialization and refresh.
Here, I need to load the configuration information and dictionary information into the Redis cache after the springboot program is started. I can write as follows:

@Component // Note that this is also a required annotation. spring needs to scan this class and hand it over to it for management
public class InitRedisCache implements ApplicationListener<ContextRefreshedEvent> {
    static final Logger logger = LoggerFactory.getLogger(InitRedisCache.class);
 
    @Autowired
    private SysConfigService sysConfigService;
 
    @Autowired
    private SysDictService sysDictService;
 
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        logger.info("-------Load configuration information start-------");
        sysConfigService.loadConfigIntoRedis();
        logger.info("-------Load configuration information end-------");
 
        logger.info("-------Load dictionary information start-------");
        sysDictService.loadDictIntoRedis();
        logger.info("-------Load dictionary information end-------");
    }
}

Note: this method will be executed twice when used in springmvc spring projects. This is because two containers will be created when loading spring and springmvc, which will trigger the execution of this event. At this time, you only need to judge whether there is a parent container in the 'onApplicationEvent' method.

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
        if(event.getApplicationContext().getParent() == null){//root application context has no parent, he is the boss
            //The logical code that needs to be executed. This method will be executed after the spring container initialization is completed.
        }
}

summary

The way of executing code at the start of the project. The above methods are integrated after the network collection, which is convenient for everyone to consult.


--------
Copyright notice: This article is the original article of CSDN blogger "bright moon" and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/sheinenggaosuwo/article/details/106222181

Topics: Java kafka Spring Distribution