Гексагональная архитектура с пружиной и модулями - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь реализовать шестиугольную архитектуру поверх приложения Spring Boot с несколькими модулями Maven. Основная идея зависеть от абстракций, а не от конкреций. Я создал три модуля test-core , test-adapter , test-application в основном, как описано здесь :

┌ \ pom.xml
├ \ test-core
│   ├  pom.xml
│   └─ src\com\example\core\
|                      ├─ ConfigCore.java
|                      └─ FooService.java
├ \ test-adapter
│   ├  pom.xml
|   └─ src\com\example\adapter\
|                      ├─ ConfigAdapter.java
|                      └─ FooServiceImpl.java
└ \ test-application
    ├  pom.xml
    └─ src\com\example\
               ├─ ConfigApplication.java
               └─ Application.java

Основная идея состоит в том, чтобы иметь следующие зависимости:

  • тест-адаптер зависит от тест-ядро
  • test-application зависит от test-core

и все. Однако невозможно реализовать без третьей зависимости, где test-application зависит от test-adapter . В данном примере, который я использовал, они сделали это таким образом (добавили прямую зависимость). Однако я хотел бы избежать этого, так как я хочу иметь архитектурный дизайн без такой связи. Можно ли как-то реализовать? Или я хочу слишком много? Или я неправильно понимаю архитектуру Ports-And-Adapters?

Чтобы сделать проблему более понятной, ниже вы можете найти код. FooServices.java

package com.example.core;
public interface FooService { String execute(); }

FooServiceImpl.java

package com.example.adapter;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Qualifier;
import com.example.core.FooService;
@Service
@Qualifier("fooService")
public class FooServiceImpl implements FooService {
    public String execute() { return "Hello world!"; }
}

Application.java

package com.example;
@SpringBootApplication(scanBasePackages = {"com.example"})
public class Application {
    @Autowired
    @Qualifier("fooService")
    FooService fooService;

    public static void main(String[] args) { SpringApplication.run(Application.class, args); }
    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) { return args -> { System.out.println(fooService.execute()); }; }
}

без письменной зависимости в \ test-application \ pom.xml до test-adapter

<dependency>
    <groupId>com.example</groupId>
    <artifactId>test-adapter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

Я постоянно получаю следующую ошибку

Исключительная ситуация при инициализации контекста - отмена попытки обновления: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании компонента с именем 'application': неудовлетворенная зависимость, выраженная через поле 'fooService'; вложенное исключение - org.springframework.beans.factory.NoSuchBeanDefinitionException: нет доступного квалифицирующего компонента типа 'com.example.core.FooService': ожидается как минимум 1 компонент, который квалифицируется как кандидат для автоматического подключения. Аннотации зависимостей: {@ org.springframework.beans.factory.annotation.Autowired (обязательно = true), @ org.springframework.beans.factory.annotation.Qualifier (value = fooService)}

Как видите, @Qualifier аннотация здесь не помогает. @ComponentScan(basePackages = {"com.example"}), @SpringBootApplication(scanBasePackages = {"com.example"}).

Решением является реализация следующих шагов: ConfigCore.java

package com.example.core;
@Configuration
@ComponentScan(basePackages = {"com.example.core"})
public class ConfigCore { }

ConfigAdapter.java

package com.example.adapter;
@Configuration
@ComponentScan(basePackages = {"com.example.adapter"})
public class ConfigAdapter { }

ConfigApplication.java

package com.example;
import com.example.core.ConfigCore;
import com.example.adapter.ConfigAdapter;
@Configuration
@ComponentScan(basePackages = {"com.example"})
@Import({ConfigCore.class, ConfigAdapter.class})
public class ConfigApplication { }

и поместите соответствующую зависимость (упомянутую выше) в pom.xml . В этом случае все работает отлично. Однако, как я уже говорил, я не думаю, что это правильный подход. Не могли бы вы помочь мне разобраться в возможностях устранения этой зависимости между test-adapter и test-application ?

1 Ответ

0 голосов
/ 29 июля 2019

Это на самом деле не связано с гексагональной архитектурой.

SpringBootApplication будет нуждаться в пути к классу для всех bean-компонентов, которые должны быть представлены в ApplicationContext.

Полагаю, в вашем случае этот класснаходится в тест-приложении .Если вы не поместите какую-либо зависимость в test-adapter , Конфигурации не будут загружены, поэтому ваш ComponentScan не будет работать.

Даже волшебные автоматически сконфигурированные bean-компоненты в SpringBoot должны быть объявлены впо крайней мере, в области времени исполнения в вашем pom.xml

Более того, в реализации шестиугольной архитектуры мы обычно используем модуль приложения для составления стратегии внедрения компонента.Поэтому вы должны поместить свои конфигурации в этот слой.

Адаптеры используются для взаимодействия с вашим доменом, например, как слой отдыха.

Данный пример реализации гексагональной архитектуры имеет единый модуль, где собираются приложение и адаптеры.Но если вы хотите разделить его, вы в основном получите:

  • в модуле приложения: конфигурации и * Приложение
  • в адаптере YouTube: пакет YouTube (SPI)в этом случае)
  • в адаптере покоя: контроллер и ресурсы

Но модуль приложения должен получить зависимость от каждого адаптера.

Основное назначение гексагональной архитектуры - это отделение бизнес-логики от технической части.Ничто не говорит о том, что адаптер должен быть автономным, но в любом случае это может быть ваш вариант реализации:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...