admin管理员组

文章数量:1343915

I have this application that works fine for a single job:

 interface Job {
     void foo();
 }

 class JobA implements Job {
     void foo() {...}
 }

 class JobB implements Job {
     void foo() {...}
 }

 class JobExecutor {
    
    Job job;
    // autowired constructor
    public JobExecutor(Job job) {this.job = job;}
 }
@Configuration
public class MyConfiguration {

    @ConditionalOnProperty(name = "job.name", havingValue = "jobA")
    @Bean 
    public Job jobA() {
         return new JobA();
    }

    @ConditionalOnProperty(name = "job.name", havingValue = "jobB")
    @Bean 
    public Job jobB() {
         return new JobB();
    }
    @Bean
    public JobExecutor jobExecutor(Job job) {
       return new JobExecutor(job);
    }
}

config:

 job.name = jobA # or jobB

But now I want to extend the application to take 2 jobs so the config is updated like this:

 job1.name = jobA # or jobB or jobC
 job2.name = jobA # or jobB or jobC

then the config is as follows:

@Configuration
public class MyConfiguration {

    @ConditionalOnExpression("#{'${job1.name}' == 'jobA' or '${job2.name}' == 'jobA'}")
    @Bean 
    public Job jobA() {
         return new JobA();
    }

    @ConditionalOnExpression("#{'${job1.name}' == 'jobB' or '${job2.name}' == 'jobB'}")
    @Bean 
    public Job jobB() {
         return new JobB();
    }

    @ConditionalOnExpression("#{'${job1.name}' == 'jobC' or '${job2.name}' == 'jobC'}")
    @Bean 
    public Job jobC() {
         return new JobC();
    }
}

then the Job classes are as follows (where every job is a subtype of Job):

 interface Job {
     void foo();
 }

 class JobA implements Job {
     void foo() {...}
 }

 class JobB implements Job {
     void foo() {...}
 }

 class JobC implements Job {
     void foo() {...}
 }

 class JobExecutor {
    
    Job job1;
    Job job2;
    // autowired constructor -- spring complains about multiple beans.
    public JobExecutor(Job job1, job2) { .... }
 }

but the problem comes when spring tries to autowire the Job classes because now there are two and it is also possible that the job1 and job2 are configured to the same Job eg JobA.. in this case it works fine because only one bean of the Job type is created

but how to use mutliple jobs ? I thought about using the @Qualifier tag but this is not really possible because the job comes from config

I have this application that works fine for a single job:

 interface Job {
     void foo();
 }

 class JobA implements Job {
     void foo() {...}
 }

 class JobB implements Job {
     void foo() {...}
 }

 class JobExecutor {
    
    Job job;
    // autowired constructor
    public JobExecutor(Job job) {this.job = job;}
 }
@Configuration
public class MyConfiguration {

    @ConditionalOnProperty(name = "job.name", havingValue = "jobA")
    @Bean 
    public Job jobA() {
         return new JobA();
    }

    @ConditionalOnProperty(name = "job.name", havingValue = "jobB")
    @Bean 
    public Job jobB() {
         return new JobB();
    }
    @Bean
    public JobExecutor jobExecutor(Job job) {
       return new JobExecutor(job);
    }
}

config:

 job.name = jobA # or jobB

But now I want to extend the application to take 2 jobs so the config is updated like this:

 job1.name = jobA # or jobB or jobC
 job2.name = jobA # or jobB or jobC

then the config is as follows:

@Configuration
public class MyConfiguration {

    @ConditionalOnExpression("#{'${job1.name}' == 'jobA' or '${job2.name}' == 'jobA'}")
    @Bean 
    public Job jobA() {
         return new JobA();
    }

    @ConditionalOnExpression("#{'${job1.name}' == 'jobB' or '${job2.name}' == 'jobB'}")
    @Bean 
    public Job jobB() {
         return new JobB();
    }

    @ConditionalOnExpression("#{'${job1.name}' == 'jobC' or '${job2.name}' == 'jobC'}")
    @Bean 
    public Job jobC() {
         return new JobC();
    }
}

then the Job classes are as follows (where every job is a subtype of Job):

 interface Job {
     void foo();
 }

 class JobA implements Job {
     void foo() {...}
 }

 class JobB implements Job {
     void foo() {...}
 }

 class JobC implements Job {
     void foo() {...}
 }

 class JobExecutor {
    
    Job job1;
    Job job2;
    // autowired constructor -- spring complains about multiple beans.
    public JobExecutor(Job job1, job2) { .... }
 }

but the problem comes when spring tries to autowire the Job classes because now there are two and it is also possible that the job1 and job2 are configured to the same Job eg JobA.. in this case it works fine because only one bean of the Job type is created

but how to use mutliple jobs ? I thought about using the @Qualifier tag but this is not really possible because the job comes from config

Share Improve this question asked 3 hours ago kawikawikawikawi 92 bronze badges New contributor kawikawi is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
Add a comment  | 

1 Answer 1

Reset to default 0

Use a Map<String, Job> injection pattern and dynamically select based on config values

Spring can inject all beans of type Job into a Map<String, Job>, where the bean name is the key.

This allows you to use configuration properties like job1.name and job2.name to look up the right bean at runtime, without relying on multiple conditional bean definitions.

1. Define jobs as regular beans with specific names

@Configuration
public class MyConfiguration {

    @Bean("jobA")
    public Job jobA() {
        return new JobA();
    }

    @Bean("jobB")
    public Job jobB() {
        return new JobB();
    }

    @Bean("jobC")
    public Job jobC() {
        return new JobC();
    }

    @Bean
    public JobExecutor jobExecutor(
            Map<String, Job> jobMap,
            @Value("${job1.name}") String job1Name,
            @Value("${job2.name}") String job2Name) {

        Job job1 = jobMap.get(job1Name);
        Job job2 = jobMap.get(job2Name);

        return new JobExecutor(job1, job2);
    }
}

2. Your JobExecutor class

public class JobExecutor {

    private final Job job1;
    private final Job job2;

    public JobExecutor(Job job1, Job job2) {
        this.job1 = job1;
        this.job2 = job2;
    }

    public void execute() {
        job1.foo();
        job2.foo();
    }
}

3. Your application.properties

job1.name=jobA
job2.name=jobB

No need for @ConditionalOnExpression or @ConditionalOnProperty on every bean

本文标签: javaMultiple beans in contexthow to dynamically select based on configStack Overflow