← Назад к вопросам
Как внедрить все реализации в интерфейсе
2.0 Middle🔥 71 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как внедрить все реализации в интерфейсе
Задача и контекст
Внедрение всех реализаций интерфейса (injection of all implementations) - это техника, позволяющая получить все компоненты, которые реализуют определённый интерфейс, в один список или карту. Это полезно для создания расширяемых архитектур.
1. Spring Framework - List injection
Базовый пример
import org.springframework.stereotype.Component;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
// Интерфейс стратегии обработки платежей
public interface PaymentProcessor {
boolean supports(String type);
void process(double amount);
}
// Реализация 1
@Component
public class CreditCardPaymentProcessor implements PaymentProcessor {
@Override
public boolean supports(String type) {
return "credit_card".equals(type);
}
@Override
public void process(double amount) {
System.out.println("Processing credit card payment: " + amount);
}
}
// Реализация 2
@Component
public class PayPalPaymentProcessor implements PaymentProcessor {
@Override
public boolean supports(String type) {
return "paypal".equals(type);
}
@Override
public void process(double amount) {
System.out.println("Processing PayPal payment: " + amount);
}
}
// Реализация 3
@Component
public class CryptocurrencyPaymentProcessor implements PaymentProcessor {
@Override
public boolean supports(String type) {
return "crypto".equals(type);
}
@Override
public void process(double amount) {
System.out.println("Processing crypto payment: " + amount);
}
}
// Сервис, который внедряет все реализации
@Service
public class PaymentService {
private final List<PaymentProcessor> paymentProcessors;
// Spring автоматически собирает все реализации PaymentProcessor в List
@Autowired
public PaymentService(List<PaymentProcessor> paymentProcessors) {
this.paymentProcessors = paymentProcessors;
}
public void processPayment(String type, double amount) {
for (PaymentProcessor processor : paymentProcessors) {
if (processor.supports(type)) {
processor.process(amount);
return;
}
}
throw new IllegalArgumentException("Unsupported payment type: " + type);
}
}
2. Внедрение в карту (Map)
Использование @Qualifier для организации
// Интерфейс
public interface NotificationService {
void send(String message);
}
// Реализации с квалификаторами
@Component("emailNotification")
public class EmailNotificationService implements NotificationService {
@Override
public void send(String message) {
System.out.println("Sending email: " + message);
}
}
@Component("smsNotification")
public class SmsNotificationService implements NotificationService {
@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
@Component("pushNotification")
public class PushNotificationService implements NotificationService {
@Override
public void send(String message) {
System.out.println("Sending push: " + message);
}
}
// Сервис, собирающий все в карту
@Service
public class NotificationDispatcher {
private final Map<String, NotificationService> notificationServices;
@Autowired
public NotificationDispatcher(Map<String, NotificationService> services) {
// Карта автоматически собирается из всех @Component
this.notificationServices = services;
}
public void notify(String channel, String message) {
NotificationService service = notificationServices.get(channel);
if (service != null) {
service.send(message);
} else {
throw new IllegalArgumentException("Unknown notification channel: " + channel);
}
}
public void notifyAll(String message) {
notificationServices.values().forEach(s -> s.send(message));
}
}
3. Пользовательские конфигурации
С использованием @Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
// Интерфейс стратегии валидации
public interface Validator {
String getName();
boolean validate(Object input);
}
// Реализации
public class EmailValidator implements Validator {
@Override
public String getName() {
return "email";
}
@Override
public boolean validate(Object input) {
return input instanceof String && ((String)input).contains("@");
}
}
public class PhoneValidator implements Validator {
@Override
public String getName() {
return "phone";
}
@Override
public boolean validate(Object input) {
return input instanceof String && ((String)input).matches("\\d{10}");
}
}
// Конфигурация
@Configuration
public class ValidatorConfiguration {
@Bean
public EmailValidator emailValidator() {
return new EmailValidator();
}
@Bean
public PhoneValidator phoneValidator() {
return new PhoneValidator();
}
// Собираем все валидаторы в один бин
@Bean
public List<Validator> validators(
EmailValidator emailValidator,
PhoneValidator phoneValidator) {
return List.of(emailValidator, phoneValidator);
}
}
// Использование
@Service
public class ValidationService {
private final List<Validator> validators;
private final Map<String, Validator> validatorMap;
@Autowired
public ValidationService(List<Validator> validators) {
this.validators = validators;
this.validatorMap = validators.stream()
.collect(java.util.stream.Collectors.toMap(
Validator::getName,
v -> v
));
}
public boolean validate(String type, Object input) {
return validatorMap.containsKey(type) &&
validatorMap.get(type).validate(input);
}
}
4. Advanced: ObjectProvider для гибкого доступа
import org.springframework.beans.factory.ObjectProvider;
public interface DataConverter {
String getFormat();
String convert(Object data);
}
@Component("jsonConverter")
public class JsonConverter implements DataConverter {
@Override
public String getFormat() {
return "json";
}
@Override
public String convert(Object data) {
return "{data: " + data + "}";
}
}
@Component("xmlConverter")
public class XmlConverter implements DataConverter {
@Override
public String getFormat() {
return "xml";
}
@Override
public String convert(Object data) {
return "<data>" + data + "</data>";
}
}
@Service
public class ConversionService {
private final ObjectProvider<DataConverter> converterProvider;
@Autowired
public ConversionService(ObjectProvider<DataConverter> converterProvider) {
// ObjectProvider позволяет ленивую загрузку и доступ к метаданным
this.converterProvider = converterProvider;
}
public String convert(String format, Object data) {
// getIfAvailable() - безопасное получение одного
DataConverter converter = converterProvider.stream()
.filter(c -> c.getFormat().equals(format))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown format: " + format));
return converter.convert(data);
}
public void listAllConverters() {
converterProvider.stream()
.map(DataConverter::getFormat)
.forEach(System.out::println);
}
}
5. Сложный пример: Registry pattern
public interface Command {
String getName();
void execute(String[] args);
}
@Component
public class HelpCommand implements Command {
@Override
public String getName() {
return "help";
}
@Override
public void execute(String[] args) {
System.out.println("Help: Available commands...");
}
}
@Component
public class ExitCommand implements Command {
@Override
public String getName() {
return "exit";
}
@Override
public void execute(String[] args) {
System.exit(0);
}
}
// Registry для команд
@Service
public class CommandRegistry {
private final Map<String, Command> commands = new java.util.HashMap<>();
@Autowired
public CommandRegistry(List<Command> commandList) {
// Регистрируем все команды
for (Command cmd : commandList) {
commands.put(cmd.getName(), cmd);
}
}
public void execute(String name, String[] args) {
Command command = commands.get(name);
if (command != null) {
command.execute(args);
} else {
System.out.println("Unknown command: " + name);
}
}
public Set<String> getAvailableCommands() {
return commands.keySet();
}
}
6. Обработка порядка внедрения
import org.springframework.core.annotation.Order;
public interface Filter {
void apply(String data);
}
@Component
@Order(1) // Порядок выполнения
public class LoggingFilter implements Filter {
@Override
public void apply(String data) {
System.out.println("Logging: " + data);
}
}
@Component
@Order(2)
public class ValidationFilter implements Filter {
@Override
public void apply(String data) {
System.out.println("Validating: " + data);
}
}
@Component
@Order(3)
public class TransformationFilter implements Filter {
@Override
public void apply(String data) {
System.out.println("Transforming: " + data);
}
}
@Service
public class FilterChain {
private final List<Filter> filters;
@Autowired
public FilterChain(List<Filter> filters) {
// Фильтры будут в порядке @Order
this.filters = filters;
}
public void process(String data) {
for (Filter filter : filters) {
filter.apply(data);
}
}
}
Ключевые пункты
- List injection - Spring собирает все реализации автоматически
- Map injection - использует имена бинов как ключи
- @Qualifier - уточняет конкретную реализацию
- @Order - управляет порядком в списке
- ObjectProvider - для гибкого доступа и ленивой загрузки
- Registry pattern - классический подход для нескольких реализаций
Это позволяет легко добавлять новые реализации без изменения существующего кода (Open/Closed принцип SOLID).