同一个项目中的多个Spring Boot应用实现CQRS - itnext


展示了如何使用两种不同的代码路径实现 CQRS:

  • 命令部分通过Spring Data JPA 实现
  • 通过jOOQ的查询部分

用例是一个银行应用程序,它提供了一个 REST 层,允许客户端调用任何部分。
在同一个项目中创建另一个带注释@SpringBootApplication的类:
@SpringBootApplication
public class GeneratorApplication {
    @Bean
    public CommandLineRunner run() {
        var template = new RestTemplate();
        return args -> {
            var operation = generateRandomOperation();          // 1
            LongStream.range(0, Long.parseLong(args[0]))        
// 2
                .forEach(
                    operation -> template.postForObject(        
// 3
                       
"http://localhost:8080/operation",
                        operation,
                        Object.class));
        };
    }
    public static void main(String[] args) {
        new SpringApplicationBuilder(GeneratorApplication.class)
                .run(args);
    }
}

  1. Operation以某种方式生成随机
  2. 从参数中获取调用次数
  3. 调用主 Web 应用程序的 URL

当我在另一个 Web 应用程序之后启动此应用程序时,它失败了。有两个原因:
  1. 两个应用程序共享相同的 Maven POM。由于 位于spring-boot-starter-web类路径上,因此生成器应用程序会尝试启动 Tomcat。它失败是因为第一个应用程序确实绑定了默认端口。
  2. Spring Boot 默认依赖组件扫描。因此,Web 应用程序扫描生成器应用程序及其声明的 bean 并创建它们。可以通过这种方式重新定义一些 bean。但是,webapp 也会创建CommandLineRunner上面的bean。因此,当它的服务器还没有准备好时,它“向自己发布”。

最直接的解决方案是将每个应用程序的类移动到它们自己专用的 Maven 模块中。您需要在每个模块中创建一个 POM,其中只包含必要的依赖项。另外,我需要在 webapp 的运行器中使用几个类。虽然我可以在另一个模块中复制它们,但这是额外的工作和复杂性。
为了防止类路径扫描,我们将每个应用程序类移动到它的包中。请注意,当包具有父子关系时它不起作用:它们必须是兄弟姐妹。
要创建特定类的 bean,我们需要根据它们的性质依赖特定的注释:
  • 对于 JPA 实体,@EntityScan, 指向要扫描的包
  • 对于 JPA 存储库,@EnableJpaRepositories, 指向要扫描的包
  • 对于其他类,@Import指向要从中生成 bean 的类

最后一步是防止生成器应用程序启动网络服务器。您可以在启动应用程序时对其进行配置。
@SpringBootApplication
@EnableJpaRepositories("org.hazelcast.cqrs")                    // 1
@EntityScan(
"org.hazelcast.cqrs")                               // 2
public class GeneratorApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(GeneratorApplication.class)
                .web(WebApplicationType.NONE)                  
// 3
                .run(args);
    }
   
// Command-line runner
}

  1. 扫描 JPA 存储库
  2. 扫描 JPA 实体
  3. 阻止 Web 服务器启动

它按预期工作,我们终于可以从设置中获益。