带有弹簧和模块的六角形建筑

时间:2019-01-22 00:17:50

标签: java spring maven architecture microservices

我正在尝试通过具有多个Maven模块的Spring Boot应用程序来实现Hexagonal体系结构。主要思想要依靠抽象而不是具体。 我基本上按照here所述创建了三个模块 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-core
  • 测试应用取决于测试核心

仅此而已。但是,如果没有 test-application 依赖于 test-adapter 的第三项依赖,则无法实现。在给定的示例中,我用他们通过这种方式(添加了直接依赖关系)来完成此操作。但是,我想避免这种情况,因为我希望在没有这种耦合的情况下进行架构师设计。 有可能以某种方式实施吗?还是我想要太多?还是我错误地理解了端口和适配器的体系结构?

为使问题更清楚,您可以在下面找到代码。 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'的bean时出错:未通过字段'fooService'表示的依赖关系;嵌套的异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为'com.example.core.FooService'的合格Bean:至少应有1个可以作为自动装配候选的Bean。依赖注释:{@ org.springframework.beans.factory.annotation.Autowired(required = 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 :(得分:0)

这与六边形建筑并没有真正的联系。

SpringBootApplication将需要在类路径中所有要在ApplicationContext中公开的bean。

我想在您的情况下,此类位于 test-application 中。 如果您不对 test-adapter 施加任何依赖性,则不会加载配置,因此ComponentScan不起作用。

至少必须在pom.xml的运行时范围中声明SpringBoot中甚至魔术自动配置的bean

此外,在六角体系结构实现中,我们通常使用应用程序模块来构成bean注入策略。因此,您应该将配置放入这一层。

适配器用于与您的域进行交互,例如Rest层。

给定的hexagonal architecture implementation example具有一个用于收集应用程序和适配器的模块。但是,如果要拆分它,基本上可以得到:

  • 在应用程序模块中:配置和* Application
  • 在youtube适配器中:youtube软件包(在这种情况下为SPI)
  • 在休息适配器中:控制器和资源

但是应用程序模块将必须获得对每个适配器的依赖。

hexagonal architecture的主要目的是将业务逻辑与技术部分分离。没有说明适配器应该是独立的,但是无论如何它可以是您的实现选择:)