Maven聚合与继承

聚合

考虑这样一个场景,如果我们要开发一个电商系统,按照现在流行的微服务架构,肯定是希望前端和后端独立成两个项目分别进行开发和部署,但前端和后端很多时候有共同的业务。比如,笔者就曾经遇到后端可以帮助用户下单,逻辑与前端用户下单的业务逻辑一致,如果两个项目独立开发,那么下单的代码势必要在两个项目中重复编写,未来如果下单的逻辑有变化,两个项目也要进行修改。Maven的聚合特性能够把不同项目的各个模块聚合在一起构件,让我们避免上面的烦恼。

我们还是用代码来举例,假设我们有个hello项目,我们在这个项目划分三个层:pojo、service和app。pojo层中有个User对象,用来装载用户的姓名,service层有个HelloService类,提供一个返回String类型的sayHello(User user)业务方法,app层负责调用service层的业务方法。现在我们将通过这个hello项目来实现Maven的聚合。

我们先创建一个名为hello的空项目:

 

 

然后选择Module,创建quickstart为骨架创建一个名为hello-parent的Maven项目:

 

 

hello-parent项目创建完毕后,我们在pom.xml文件中的坐标处加入<packaging>pom</packaging>:

<groupId>com.leolin.mvnbook</groupId>
<artifactId>hello-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

  

然后,我们再按照之前的方式创建一个新的Module,名为hello-pojo:

 

我们在hello-pojo项目pom.xml文件的坐标处,加入<packaging>jar</packaging>:

<artifactId>hello-pojo</artifactId>
<packaging>jar</packaging>

 

我们对hello-pojo项目进行Maven→Reimport,然后删除com.leolin.mvnbook下的App文件,并创建pojo包,在pojo包下新建User类:

package com.leolin.mvnbook.pojo;

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  

我们再建立一个名为hello-service的Module:

 

hello-service创建完毕后,我们pom.xml文件中加入packaging元素,并加入对hello-pojo的依赖:

<artifactId>hello-service</artifactId>
<packaging>jar</packaging>
<dependencies>
	<dependency>
		<groupId>com.leolin.mvnbook</groupId>
		<artifactId>hello-pojo</artifactId>
		<version>1.0-SNAPSHOT</version>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
	</dependency>
</dependencies>

  

然后对hello-service进行Maven→Reimport,我们删除该项目原先的App.java文件,并创建service目录,在service目录下创建HelloService.java文件:

package com.leolin.mvnbook.service;

import com.leolin.mvnbook.pojo.User;

public class HelloService {
    public String sayHello(User user) {
        return "hello " + user.getName();
    }
}

  

我们可以看到,虽然hello-service和hello-pojo都是独立的Maven项目,但hello-service在pom中加入hello-pojo的依赖,就可以引用hello-pojo了。那么按照之前所说的,我们还有个app项目,这个app项目会依赖service,调用service的方法。现在,我们动手创建app:

 

在pom.xml文件中加入对packaging和hello-service的依赖:

<artifactId>hello-app</artifactId>
<packaging>jar</packaging>
<dependencies>
	<dependency>
		<groupId>com.leolin.mvnbook</groupId>
		<artifactId>hello-service</artifactId>
		<version>1.0-SNAPSHOT</version>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
	</dependency>
</dependencies>

  

对项目Reimport之后,我们可以在App.java文件中尝试调用HelloService中的sayHello(User user)方法:

package com.leolin.mvnbook;

import com.leolin.mvnbook.pojo.User;
import com.leolin.mvnbook.service.HelloService;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        User user = new User("Jack");
        HelloService service = new HelloService();
        System.out.println(service.sayHello(user));
    }
}

  

运行App文件,可以看到控制台打印出:

hello Jack

  

至此,我们通过Maven的聚合解决了同一个系统,不同模块独立运行部署时产生的代码冗余的问题。

继承

现在,让我们在回到开头提的电商系统,如果我们的领导,希望电商系统不仅做到前端后端分离,且前端不同模块,比如:订单模块、商品模块、物流模块,也要独立部署运行。这看上去并不是什么难题,无非就是多建几个Maven项目而已,但我们细细一想,如果我们使用的是Spring Framework框架,那么在订单、商品、物流等模块的pom文件是不是引入相同的groupId和version。也有人说,我们可以在专门在一个Maven项目中存放我们的依赖,然后将那个Maven项目引入进来,这个办法确实可行,但如果有一个项目,它仅依赖spring-core,却因为引入那个Maven项目也间接引入spring-context、spring-beans,这是不是造成没必要的冗余?

因此,Maven提供的depenencyManagement元素既能让子模块继承到父模块的元素,又能保证子模块的灵活性。代码如下:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <junit.version>4.10</junit.version>
        <spring.version>4.1.3.RELEASE</spring.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <!-- 单元测试 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <!-- Spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>${spring.version}</version>
            </dependency>
        </dependencies>


    </dependencyManagement>

  

这里使用depenencyManagement声明的依赖不会给子模块间接引入依赖,不过这段配置是会被继承的。现在,修改hello-service的pom文件如下:

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
	</dependency>
	<dependency>
		<groupId>com.leolin.mvnbook</groupId>
		<artifactId>hello-pojo</artifactId>
		<version>1.0-SNAPSHOT</version>
	</dependency>
</dependencies>

  

我们可以看到,spring-context和junit我们都没引入版本号,但Maven会去依赖hello-parent所定义的版本号。

posted @ 2020-04-25 15:06  北洛  阅读(245)  评论(0编辑  收藏  举报