Вопрос или проблема
У меня есть веб-приложение на Spring. Вот простая структура, чтобы объяснить мою проблему
java/
└── com/
└── example/
├── controller/
│ └── MyController.java // REST контроллер
├── service/
│ └── MyService.java // Интерфейс сервиса
├── client/
│ └── EC2Client.java // EC2Client
MyController
внедряет MyService
, а MyService
внедряет EC2Client
.
Существует несколько Beans EC2Client. Они используются в зависимости от региона. Регион поступает через REST API в контроллер.
Я хотел бы создать иерархию бинов на основе регионов (us-east, us-west и т.д.). Таким образом, для каждого региона у меня должен быть контроллер, сервис и бин EC2Client.
В идеале, если бы мне нужно было создать один класс бина на основе региона, я мог бы создать бины-квалификаторы. Но как мне сделать это для всей иерархии? У меня потенциально может быть более 5 регионов, поэтому я хочу сделать это динамичным по своей природе.
Ответ или решение
Для реализации иерархии бинов в вашем приложении Spring на основе региона, вы можете применить подход с динамической конфигурацией бинов через использование профилей или с помощью кастомного механизма для создания бинов на основании переданного значения региона. В данном случае мы сосредоточимся на создании динамической привязки бинов через использование @Qualifier
и кастомных фабричных методов.
Шаги по созданию иерархии бинов на основе региона
-
Создание интерфейса и классов для клиентов EC2:
Вам необходимо создать базовый интерфейс для клиента EC2 и несколько его реализаций для различных регионов.
public interface EC2Client { void performAction(); } @Component("usEastEC2Client") public class USEC2Client implements EC2Client { public void performAction() { // Логика для us-east } } @Component("usWestEC2Client") public class USWestEC2Client implements EC2Client { public void performAction() { // Логика для us-west } }
-
Создание сервисного интерфейса и его реализации:
Реализуйте интерфейс сервиса, который будет инъекцировать нужный клиент EC2 на основе переданного региона.
public interface MyService { void executeAction(String region); } @Service public class MyServiceImpl implements MyService { private final Map<String, EC2Client> ec2Clients; @Autowired public MyServiceImpl(@Qualifier("usEastEC2Client") EC2Client usEastEC2Client, @Qualifier("usWestEC2Client") EC2Client usWestEC2Client) { ec2Clients = new HashMap<>(); ec2Clients.put("us-east", usEastEC2Client); ec2Clients.put("us-west", usWestEC2Client); // Добавьте другие регионы по мере необходимости } @Override public void executeAction(String region) { EC2Client client = ec2Clients.get(region); if (client != null) { client.performAction(); } else { throw new IllegalArgumentException("Unknown region: " + region); } } }
-
Реализация контроллера:
Теперь создайте контроллер, который будет принимать запросы и передавать их в сервис.
@RestController public class MyController { private final MyService myService; @Autowired public MyController(MyService myService) { this.myService = myService; } @GetMapping("/execute/{region}") public ResponseEntity<String> executeAction(@PathVariable String region) { myService.executeAction(region); return ResponseEntity.ok("Action executed for region: " + region); } }
Дополнительные мелочи
-
Валидация региона: Убедитесь, что предоставленный регион является допустимым. Вы можете использовать перечисление (enum) для всех поддерживаемых регионов.
-
Конфигурация через @Configuration: Если вам нужно выполнить более сложную конфигурацию бинов, вы также можете использовать класс с аннотацией
@Configuration
для создания и настройки бинов в зависимости от ваших требований. -
Использование профилей: Если количество регионов стабильно и не меняется, вы можете задействовать профили Spring. Вместо создания нескольких классов вы создадите один и настроите различия через конфигурации.
Следуя приведенным выше шагам, вы создадите динамическую иерархию бинов в зависимости от региона, что обеспечит гибкость и масштабируемость для вашего приложения.