首先我们聊聊为什么要使用maven进行模块划分。 (本节内容参考maven 为何要模块划分-聚合/继承)
为了防止传递依赖,我们各个模块之间尽量用直接依赖的方式。本篇文章介绍多模块化开发,我们做过Maven项目的都知道,我们的项目一般都是分模块的,每个模块都会对应着一个POM.xml文件,它们之间通过继承和聚合(也称多模块,multi-module)相互关联。
我们换另一种思路想想,那么我们能不能一个项目就用一个模块。这样开起来很方便,简单明了,那么做起来呢,接下来我们分析一下。
假设我们有这么一个项目,整个项目构建一个war包,而每一层放到各自的Package里面。如下:
Itoo-Exam
com.tgb.itoo.exam.dao —–负责与数据库的交互,封装了hibernate的交互类
com.tgb.itoo.exam.service—-负责处理业务逻辑,放Service接口及其实现类
com.tgb.itoo.exam.web——-负责与客户端的交互,主要放action/controller,jsp等等
com.tgb.itoo.exam.util——–工具类
那么随着我们项目的扩大,Maven项目也会越来越大,那么会遇到下面的几个问题:
1、首先build整个项目的时间越来越长,尽管你一直在web层工作,但你不得不build整个项目
2、模块化体现不出来,如果我们只负责维护某个模块,因为我们所有的模块都在一个war包中,那么我们可以随意修改其他模块(权限的控制),导致版本管理混乱,冲突。同时因为模块太多,太大,不好维护。
很多人都在同时修改这个war包,将导致工作无法顺利进行。
3、pom.xml本来是可以继承、复用的,但是如果我们新建一个项目,只能依赖于这个war包,那么会把这个war包的相关的前台的东西依赖过来,导致项目管理混乱。
这样的管理是混乱的,没有遵守一个设计模式原则:“高内聚,低耦合”。相反在代码内部,所有的东西都耦合在了一起。因此我们需要划分模块。
另外,随着技术的飞速发展和各类用户对软件的要求越来越高,软件本身变得越来越复杂,设计人员开始采用各种方式进行开发,于是就有了我们的分层架构、分层模块来提高代码的清晰和重用。从而实现了系统内部的高内聚、低耦合。
模块化的好处
1、方便重用,当我们再开发一条teacher线的时候,我们只需要引用itoo-base,itoo-exam-api,这些包都是复用的,称为我们平台复用的基础类库,供所有的项目使用。这是模块化最重要的一个目的。
3、灵活性。比如我们这些公共的jar包,itoo-base,itoo-tool,itoo-exam-api等这些jar包,我们不需要再当源码,只需要deploy到nexus,其他人从nexus下载即可。代码的可维护性、可扩展性好,并且保证了项目独立性与完整性。
5、上篇文章写得DependencyManagement与dependencies,父项目中管理jar包版本。使得整个项目的测试版本与发布版本一致。
使用模块化配置,复用性强,防止pom变得过于庞大,方便构建;针对项目的管理更方便,每一个模块都是独立的,抽象出一个父类来管理第三方jar的版本,开发人员只需要开发自己的线,其他的都不用管,灵活;基于此种基础我们还可以做分布式。
上面提到了我们用父项目聚合子项目,子项目继承父项目。怎么使用maven的模块聚合和继承,构建多模块工程可以参考
Eclipse创建Maven多模块工程
先简单描述一个简单测试项目需求: (本节内容参考:Maven划分项目模块经验)
现需要开发一个用于管理用户信息项目(项目名为:edu),主要功能是管理系统使用用户信息(user)。
划分步骤为:
1. 将项目进行划分需要详细了解项目按照垂直划分(项目大的功能需求)可以划分几个模块。
2. 将划分出来的项目进行横向划分,分别分出对应的 WEB层、Service接口层、Service接口实现层、Dao层。
3. 确定项目的 GroupId(命名规则为:公司网址反写加上项目名 例如:com.hysky.edu) 和 ArtifactId(命名规则为:项目名-横向模块名-垂直模块名 例如:edu-web-user),建立项目基本工程模型。
4. 建立一个Maven父工程(packaging为POM类型)用于管理整个项目Jar包、项目所使用的插件、项目发布Maven私库地址、全局POM使用常量,所有的项目都继承这个项目配置。
5. 建立一个Maven工程(packaging为jar类型)用于管理整个项目使用的配置文件。例如 jdbc数据库连接地址、注册中心连接地址等等,所有工程需要依赖这个工程。
6. 可以建立一个Maven工程(packaging为POM类型)用于管理所有工程统一操作,使用 Maven聚合(module)所有项目,Maven会自动识别项目依赖关系,可以依次进行命令操作。
7. 将所有项目都需要使用的公共工具类可以抽取出来,新建立一个 Maven工程(packaging为jar类型),方便所有开发依赖使用工具类。
根据本人的实际工作经验,以usr项目为例,maven模块划分如下:
制定项目模块命名规则:
项目名-横向模块名-打包类型
1、项目名即为usr
2、横向模块可以划分为WEB层、Service接口层、Service接口实现层、Dao层。
本人将之分成3种类型:
3、打包类型可以划分为web(表示打成war包)、java(表示打成jar包)。
最终,把项目划分为五个模块:
由于我们是与dubbo结合的,所以
usr-cjpt-java 是消费方
usr-hxfw-java 是提供方
usr-cjpt-web和usr-hxfw-web是部署到tomcat的war应用。
模块依赖关系如下图:
关于为什么使用一个公共的maven工程来存放pojo和服务接口,再被consumer工程和provider工程依赖,可以参考
dubbo在项目中的应用
可能会让人困惑的是,为什么是把usr-hxfw-web打成war包?
在很多博客的示例中 ,说的都是把消费方和提供方打成war包,部署到tomcat中。(比如 Dubbo项目配置 这篇博客)
1、api-dubbo;——统一的接口,用来连接消费者和生产者,最后打成jar包
2、consumer-dubbo;——消费者,也就是web层,接口的调用者,最后打成war包;
3、producer-dubbo;——生产者,也就是业务层,接口的服务提供者,最后打成war包;
请记住,那些只是简单示例,不是说一定要把消费方打成war包,消费方才能调用服务。也不是说一定要把提供方打成war包,提供方才能提供服务。只要把消费方和提供方部署到tomcat容器即可。
上面usr-cjpt-web和usr-hxfw-web打成war包,部署到tomcat容器。但是应为usr-cjpt-web依赖了消费方usr-cjpt-java,以及usr-hxfw-web依赖了提供方usr-hxfw-java,所以消费方usr-cjpt-java和提供方usr-hxfw-java同样会部署到tomcat容器。
在笔者所在的公司中,usr-hxfw-web除了用于代替usr-hxfw-java打成war包,还是用于添加sql文件,并依赖自维护数据库jar包,在容器启动时执行sql脚本的;用于添加spring的appclication-context.xml,配置扫描@service等注解(即除了@Controller之外的注解)。
而usr-cjpt-web添加的appclication-context.xml,则配置扫描@Contoller等注解。
ps:上述这些spring配置不是一定要在这2个工程配置。假如它们依赖的jar包已经添加Application-context.xml进行了spring配置,则这2个工程可以不再添加Application-context.xml。因为在它们的web.xml中配置的是加载类路径下的spring文件夹下的*.xml。这也就包括了所依赖jar包下的spring文件夹下的Application-context.xml。
比如上面模块依赖中,usr-hxfw-web工程依赖了usr-hxfw-java工程,如果usr-hxfw-java工程添加了Application-context.xml,或者usr-hxfw-java工程依赖的其它jar包添加了Application-context.xml,那么,即使usr-hxfw-web工程不添加Application-context.xml,也能实现@service等注解扫描。