多模块划分的必要
通常一个复杂的大型项目会划分为多个模块,在结构化程序设计中,模块划分的原则是模块内具有高内聚度、模块间具有低耦合度
在将一个复杂项目拆分成多个模块,有利于协同开发,方便模块重用
初次上手多模块的springboot项目
1.初始化工具新建springboot项目:project-root
这里称这个处于外层的项目(project-root)为父模块,project-root直接路径下的pom.xml称之为顶层pom文件
然后对pom.xml进行修改,删除其他不用的资源文件夹,以便被所有子模块继承
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引用默认的父工程项目,这样就可以不用声明版本号-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--各个子模块加入到project-root项目中-->
<modules>
<module>project-child</module>
<module>project-server</module>
</modules>
<!--顶层依赖,作为整个项目来引用-->
<!--组织名-->
<groupId>org.example</groupId>
<!--模块名,唯一标识-->
<artifactId>project-root</artifactId>
<!--项目版本-->
<version>1.0-SNAPSHOT</version>
<name>project-root</name>
<description>顶层pom依赖</description>
<!--父工程打包方式必须是pom形式-->
<packaging>pom</packaging>
<properties>
<!--父模块properties属性能够被子模块继承和使用,可用于统一版本管理-->
<junit.version>4.13</junit.version>
<lombok.version>1.18.12</lombok.version>
</properties>
<!--
dependencyManagement标签作用:
1.用在项目顶层的pom文件中,统一管理项目的依赖和版本
2.该标签不能用在子项目的pom文件中,因为在该标签里面的依赖只是声明依赖,并不实现引入
3.这个标签里面的依赖不会主动引入到子项目中,子项目要引用这里面的依赖就需要显式声明,但是可以不用指定版本,
因为version和scope都读取自顶层pom
4.如果某个子项目自定义版本,只需要在dependencies中声明即可
dependencies标签的使用:
父项目中如果不使用dependencyManagement标签,直接使用dependencies标签,
那么所有在dependencies里的依赖都会自动引入,并默认被所有的子项目继承
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--顶层pom依赖中已经引用了spring-boot-starter-parent,因此不要在这里面重复引用-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
</dependencies>
</dependencyManagement>
<build>
<!--统一插件管理,这些插件在子模块中声明即可使用-->
<pluginManagement>
<!--spring生成可执行jar包的插件,注意不要同时org.apache.maven.plugins使用-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2.在project-root项目名上新建moudle:project-child
该子模块继承父模块project-root
这样的子模块可以有多个,都继承于父模块
子模块与子模块的耦合度要尽可能低,尽可能减少子模块之间的交叉依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--每个子模块引用唯一的引用父模块,这样引入父模块依赖的时候就可以不用指定版本号-->
<parent>
<groupId>org.example</groupId>
<artifactId>project-root</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!-- 当前模块基本信息-->
<groupId>com.example</groupId>
<artifactId>project-child</artifactId>
<!--有了父模块,子模块就不用指定版本号-->
<!--<version>0.0.1-SNAPSHOT</version>-->
<description>Demo project for Spring Boot</description>
<!-- 模块打包方式-->
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!--子模块作为依赖被引入另外一个模块,则另一个模块将会引入子模块所使用的所有依赖
另一个模块如果再次导入子模块所使用的其他依赖,则只会导入一次而不会报错
-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
</dependencies>
</project>
3.在project-root项目名上新建moudle:project-server
- 指定为主模块,该模块同样继承父模块:project-root
- 该模块里面设置springboot启动器,并且能够调用则其他所有的子模块
- 当需要调用子模块时,直接以dependency标签的方式引入即可
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引用父模块-->
<parent>
<!--组织名-->
<groupId>org.example</groupId>
<!--模块名,唯一标识-->
<artifactId>project-root</artifactId>
<!--项目版本-->
<version>1.0-SNAPSHOT</version>
</parent>
<!--主模块信息-->
<groupId>com.example</groupId>
<artifactId>project-server</artifactId>
<!--子模块默认使用与父模块一致的版本-->
<!--<version>0.0.1-SNAPSHOT</version>-->
<packaging>jar</packaging>
<name>project-server</name>
<description>主模块,用于启动springboot应用</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引用其他子模块-->
<dependency>
<groupId>com.example</groupId>
<artifactId>project-child</artifactId>
<!--因为整个工程的版本统一的,每个子模块的版本与父工程的版本一致,所以直接使用父工程版本号-->
<version>${project.version}</version>
</dependency>
<!--引用父模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.junit.vintage</groupId>-->
<!-- <artifactId>junit-vintage-engine</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
</dependencies>
<!--
多模块构建方法:
1.主模块,启动类所在的模块,该类用于调用其他子模块,在多模块中必须要指定这样一个主模块
2.一个或多个子模块,主模块要调用子模块,必须通过dependency标签来引入
3.只需要在主模块中添加打包的插件即可,不要在其他模块中添加
4.使用mvn package 打包时,选择主模块即可,凡是所依赖的子模块都会被打包进去
-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.模块测试
1.project-child模块测试类
package com.example.projectchild.entity;
import lombok.Getter;
import lombok.Setter;
/**
* @Author: wonzeng
* @CreateTime: 2020-10-08
*/
@Setter
@Getter
public class User {
private Integer id;
private String name;
public User() {
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
}
2.project-server模块测试类
在这个模块的pom.xml中以依赖形式引入project-child模块,这样就能使用User这个测试类
package com.example.projectserver.controller;
import com.example.projectchild.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
/**
* @Author: wonzeng
* @CreateTime: 2020-10-08
*/
@RestController
public class HelloController {
public HelloController() {
}
/**
* 出现异常:
* org.springframework.http.converter.HttpMessageNotWritableException
* 是因为 实体User没有提供setter和getter方法,所以无法转化为json
*/
@GetMapping(value={"/hello","/"})
public User hello(){
System.out.println("Hello World!");
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("当前时间:"+localDateTime.toLocalTime().toString());
User user = new User(101,"张三");
return user;
}
}
3.project-server模块启动器
启动后访问:http://localhost:8080/ 说明模块整合成功
package com.example.projectserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ChildServerApplication {
public static void main(String[] args) {
SpringApplication.run(ChildServerApplication.class, args);
}
}
除了直接运行main方法,还可以在springboot的应用的根目录下运行命令:
mvn spring-boot:run
4.打包和启动
打包执行以下命令:
mvn clear
mvn package
切换到打包输出的目录再对项目xxx.jar执行命令:
java -jar xxx.jar