简体   繁体   中英

Spring, injecting a list of beans with only specific beans included

In Spring, when I inject a list of beans, I only want to inject specific implementations of the interface, when used from different places. Is this possible to do? What would be the cleanest way to configure this? For example, I have the following validators:

public interface Validator {
    Optional<Error> validate(MultipartFile file);
}

public class Validator1 implements Validator {
    public Optional<Error> validate(MultipartFile file) {
        // do stuff
    }
}

public class Validator2 implements Validator {
    public Optional<Error> validate(MultipartFile file) {
        // do stuff
    }
}

public class Validator3 implements Validator {
    public Optional<Error> validate(MultipartFile file) {
        // do stuff
    }
}

And then I have a validation service which looks similar to this:

public class ValidationService {
    @Autowired
    private List<Validator> validators;

    public List<Error> validate(MultipartFile file) {
        List<Error> errors = new ArrayList<>();
        validators.forEach(v -> {
            Optional<Error> error = v.validate(file);
            if (error.isPresent()) {
                errors.add(error.get());
            }
        });
        return errors;
    }
}

And then I have some services, which use the ValidationService, eg:

public class Service1 {

    @Autowired
    private ValidationService validationService;

    public void doStuff(MultipartFile file) {
        ...
        validationService.validate(file);
        ...
    }
}

public class Service2 {

    @Autowired
    private ValidationService validationService;

    public void doStuff(MultipartFile file) {
        ...
        validationService.validate(file);
        ...
    }
}

When Service1 calls validate, I only want Validator1 and Validator2 to have been injected into the ValidatorService. When Service2 calls validate, I only want Validator2 and Validator3 to have been injected into the ValidatorService.

Hope I have explained this clearly enough. Thanks in advance for any help offered.

Create the bean like this with @Qualifier annotations --

@Qualifier("validator1")
public class Validator1 implements Validator {
   public Optional<Error> validate(MultipartFile file) {
            // do stuff
        }
}

@Qualifier("validator2")
public class Validator2 implements Validator {
    public Optional<Error> validate(MultipartFile file) {
        // do stuff
    }
}
@Qualifier("validator3")
public class Validator3 implements Validator {
    public Optional<Error> validate(MultipartFile file) {
        // do stuff
    }
}

and inject it like this ---

@Autowired("validator1")
private ValidationService validationService;

Update

You can also create a bean collection for all the validators like this -

@Bean("validators")
public List<Validator> validatorList(Validator1 validator1, Validator2 validator2, Validator3 validator3) {
    return Arrays.asList(validator1, validator2, validator3);
}

and the inject the list bean as --

@Autowired("validators")
private List<Validator> validators;

Check this page fore a detailed example - https://www.baeldung.com/spring-injecting-collections

This is likely not the best way to do this. Here is how I would do it, based on my current understanding of Spring.

Summary:

  1. Create a bean method for each collection of implementations. In your case, create a bean method for a List<Validator> that contains Validator1 and Validator2 and create a second List<Validator> that contains Validator2 and Validator3.
  2. Inject the desired List using @Qualifier.

The code should be something like this:

@Configuration
public class ValidatorLists
{
    private void getAndAddBean(
        final ApplicationContext applicationContext,
        final List<Validator> list,
        final String beanName)
    {
        final Validator bean;

        bean = applicationContext.getBean(beanName);
        if (bean != null)
        {
            list.add(bean);
        }
    }

    @Bean("ValidatorList1")
    public List<Validator> validatorList1(final ApplicationContext applicationContext)
    {
        Validator bean;
        final List<Validator> returnValue = new LinkedList<>();

        getAndAddBean(applicationContext, returnValue, "ValidatorImpl1");
        getAndAddBean(applicationContext, returnValue, "ValidatorImpl2");
        
        return returnValue;
    }

    @Bean("ValidatorList2")
    public List<Validator> validatorList2(final ApplicationContext applicationContext)
    {
        Validator bean;
        final List<Validator> returnValue = new LinkedList<>();

        getAndAddBean(applicationContext, returnValue, "ValidatorImpl2");
        getAndAddBean(applicationContext, returnValue, "ValidatorImpl3");
        
        return returnValue;
    }
}

Then reference the list by qualifier.

    @Autowired
    @Qualifier("ValidatorList1")
    private List<Validator> validators;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM