Total Pageviews

2020/01/08

[Spring] How to invoke a spring component dynamically

Requirement
Assume I have 2 job classes, I will use command line to execute with job name, and program invoke specific Job class to do something.

Command line looks like:
>java -jar batch-0.0.1-SNAPSHOT.jar -name Job1

The two Job class are as bellows:
package com.test.batch.job;

import com.test.batch.service.Service1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component ("Job1")
public class Job1 implements Job{

    @Autowired
    private Service1 service1;

    public void execute() {
        log.debug("execute job1");
        service1.sayHello();
    }

}



package com.test.batch.job;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component("Job2")
@Slf4j
public class Job2 implements Job {

    @Override
    public void execute() {
        log.debug("execute job2");
    }

}

Invoke specific Job class based on the argument which provide by user:
package com.test.batch.service;

import com.test.batch.job.Job;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class JobExecutor {

    @Autowired
    private ApplicationContext ctx;

    public void execute(String argument) {
        try {
            // get bean by name
            Job job = (Job) ctx.getBean(argument);
            job.execute();
        } catch (Exception e) {
            String error = "Fail to execute batch job, you provide job name is " + argument;
            log.error(error, e);
        }
    }

}


Command line runner class:
package com.test.batch;

import com.beust.jcommander.JCommander;
import com.test.batch.parameter.BatchJobArgument;
import com.test.batch.service.JobExecutor;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class BatchCommandLineRunner implements CommandLineRunner {

    @Autowired
    private JobExecutor jobExecutor;

    @Override
    public void run(String... args) throws Exception {
        BatchJobArgument arguments = new BatchJobArgument();

        JCommander jCommander = JCommander.newBuilder().build();
        jCommander.addObject(arguments);
        jCommander.parse(args);

        if(arguments.isHelp()){
            jCommander.usage();
            return;
        }

        log.debug("arguments = {}", arguments);

        if(Strings.isNullOrEmpty(arguments.getName())) {
            log.debug("Please assign job name (ex. -name Job1)");
        }else{
            jobExecutor.execute(arguments.getName());
        }
    }

}



No comments: