创建父子工程包含多个Springboot模块(2021.05.12)

创建Maven父子模块工程其实很简单。父工程只管理依赖,不牵扯代码和逻辑,子工程进行拆分开发。但是如果一个项目中包含多个Springboot子项目就稍微有点问题。

我们有这样的需求:

假设我们要创建一个名为wormhole-parent的父项目,其中包含两个Springboot子项目,分别叫steward和sink。

steward模块需要依赖sink模块,但是sink也需要调用steward的方法(循环依赖问题)

steward模块和sink模块都有自己各自的接口,steward模块中的启动类作为真正的启动类

上面的需求会遇到如下问题:

  • 每个Springboot子模块创建时都有启动类,如何指定steward模块的启动类为真正的启动类
  • 两个子模块之间存在循环依赖如何解决
  • 编译打包时会遇到的一些问题如何解决

下面将就上面可能遇到的问题一一解释。

第一步,创建一个maven父项目(创建Springboot父项目也是可以的,但是没有必要而且会遇到一些问题),删除idea自动创建的src目录,添加开发web项目必须的依赖(如果需要其他两个子模块的通用依赖当然也是需要添加的):

<!--添加Springboot父项目依赖,不添加的话引入Springboot依赖的时候需要手动指定版本-->
<parent>
  <groupId>org.springframework.boot</groupId>
  <version>2.4.4</version>
  <artifactId>spring-boot-starter-parent</artifactId>
</parent>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

第二步,创建两个Springboot子项目(创建Maven子项目也可以)并删除如下内容:

  • sink模块的启动类(因为我们规划使用steward模块的启动类作为主启动类)

  • sink模块中的打包插件(确保只保留steward模块中一个该插件,如果父项目中也有此插件需要一并删除)

    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    

第三步,在pom文件中分别添加如下配置,保证模块之间的父子关系

  • 父模块中,添加所有子模块信息

    <modules>
    	<module>steward</module>
      <module>sink</module>
    </modules>
    
  • 子模块(sink、steward)中添加父模块信息

    <parent>
    	<artifactId>wormhole</artifactId>
      <groupId>it.aspirin</groupId>
      <version>1.0.0</version>
    </parent>
    

第四步,在steward模块pom文件中添加sink作为依赖

<dependencies>
  <dependency>
    <groupId>it.aspirin</groupId>
    <artifactId>sink</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>

第五步,注意包的扫描问题,如果多个子模块需要扫描的包不一致,需要在主启动类上进行配置,确保Springboot可以扫描到所有需要注册的类

@SpringBootApplication(scanBasePackages={"it.aspirin.steward","it.aspirin.sink"})
public class StewardApplication{
  //...
}

第六步,项目的配置文件放在主启动类所在的模块,打包好jar以后打包的也是主启动类所在的jar。

第七步,在父文件中修改打包方式为pom方式:<packaging>pom</packaging>

第八步,把非主启动类所在模块以外的所有模块的测试方法禁用掉,否则在编译打包阶段会报错。

//禁用sink的测试方法
@Disabled
@SpringBootTest
class SinkApplicationTests {
    @Test
    void contextLoads() {
    }
}

经过上面八步配置,这个有两个Springboot子模块的启动类就创建成功了。此时只有一个问题没有解决,就是如何解决循环依赖问题,如果不需要解决循环依赖问题,就可以先写代码测试了:

在steward中写一个Controller

@RestController
public class StewardController{
  @Resource
  User user;//该类来自于sink,由于我们引入依赖了,所以可以注入进来
  @GetMapping("/steward")
  public String hello(){
    return "hello"+user;
  }
}

写一个Service

@Service
public class StewardService{
  public String steward(){
    return "from steward";
  }
}

在sink中写一个实体类

@Component
@ConfigurationProperties(value="user")//表示从配置文件注入
public class User{
  private String name;
  private String age;
  //省略get/set方法,toString方法
}

写一个Controller,在这里一起解决了循环依赖问题。

@RestController
public class SinkController(){
  
  @GetMapping("/sink/hello")
  public String hello(){
    return "hello";
  }
  
  //测试反射,通过反射的方式解决循环依赖问题
  @GetMapping("/sink/ref")
  public String ref(){
    Class<?> TestServiceClass = Class.forName("it.aspirin.steward.service.StewardService");
    Method steward = TestServiceClass.getMethod("steward");
    Object stewardService = TestServiceClass.newInstance();
    //content是调用steward模块的steward方法返回的内容
    Object content = steward.invoke(stewardService);
    return "hello "+content;
  }
}

注意事项:

  • 不管有多少个Springboot子模块,必须只能保留一个启动类,其余删除
  • 没有启动类的模块无法使用springboot的测试,如果需要测试需要将测试放到有启动类的test文件夹下
  • 必须只能保留一个上文提到的插件,否则子模块在编译的时候会提示找不到主类而失败(因为其他模块的主类被我们删除了)
  • 父子模块的关系要配置好,配置好以后,idea的maven插件会显示父模块为root
  • 经过配置以后在使用方式上可以认为逻辑上是一个模块,即在sink中注入的类在steward中可以无障碍拿到注入的对象。(由于sink不包含steward的依赖,因此无法通过注入获得)
  • 如果项目中真的存在循环依赖一般是模块设计不合理导致的,但是由于某些原因,即使知道不合理也没法做出改变,可以通过上面的方式,首先配置一个模块配置依赖另外一个模块,另外一个模块再通过反射的方式得到另一个模块中的类和方法
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值