maven学习系列篇
maven
1、maven核心
先介绍一下核心:使用maven管理项目。具体分为:依赖管理、项目构建、分模块开发
依赖管理: maven对项目的第三方构件(jar包)进行统一管理。向工程中加入jar包不要手工从其它地方拷贝,通过maven定义jar包的坐标,自动从maven仓库中去下载到工程中。
注意:如果jar包A依赖jar包B,那么在导入jar包A的时候,maven会自动导入jar包B进来;
项目构建: maven提供一套对项目生命周期管理的标准,开发人员、和测试人员统一使用maven进行项目构建。项目生命周期管理:编译、测试、打包、部署、运行。
maven对工程分模块构建,提高开发效率。(稍后介绍)
1.1、maven坐标
Maven的一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等。为了能自动化的解析任何一个Java构件,Maven必须将这些Jar包或者其他资源进行唯一标识,这是管理项目的依赖的基础,也就是我们要说的坐标。包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样才能才其它项目中进行依赖引用。坐标的定义元素如下:
groupId:项目组织唯一的标识符,实际对应JAVA的包的结构 (一般写公司的组织名称 eg:com.jidong,com.alibaba)
artifactId: 项目的名称
version:定义项目的当前版本
例如:要引入druid,只需要在pom.xml配置文件中配置引入druid的坐标即可:
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
maven就会帮我们从仓库中下载对应的jar包到我们的项目中来,而不在需要自己手动来进行导包到自己的项目中。
1.2、maven命令作用
clean 用来清除编译后的文件(target文件夹里面的)【一般清缓存】;
compile 编译,将.java文件编译成为.class文件;
test 执行单元测试,注意:在idea中执行时,可以看一下工作空间选择的是否是不是对的,执行mvn test之后,可以看到单元测试有运行结果。
package 打包 (javaSe-->jar, javaweb-->war),通过执行这个即可,以后没有必要的话不需要执行install命令再来安装到本地仓库中去了
install 把项目打包之后安装到本地仓库
1.3、生命周期
具体的maven周期可以分为两个:clean和clean之外的,分为两个生命周期。
当我们执行了install 也会执行compile test package
那么这里有时候就会产生问题,这里没有将旧的jar包清除掉,所以我们应该直接执行mvn clean install命令,先将缓存清除掉,然后再来进行安装。
那么所有的声明周期都会来进行执行。
1.4、maven依赖管理
导入依赖坐标,无需手动导入jar包就可以引入jar。在pom.xml中使用标签引入依赖。做项目/工作里面 都有整套的依赖的, 不需要背诵的.
去Maven官网找, 赋值,粘贴. http://mvnrepository.com/
导入几个依赖来查看一下:
导入junit测试类,那么在test目录下的类中就可以来进行测试了,不需要额外的来引入包:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
对应的测试类是:
public class DemoTest {
@Test
public void test1(){
System.out.println("----->hello,world<-----");
}
}
导入servlet依赖,创建Servlet,但是发现报错,原因是没有导入Servlet的坐标依赖;
只需要引入对应的servlet依赖即可,那么代码就不会报错。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
1.4.1、依赖范围
maven中不同的命令对应的依赖范围是不同的。
依赖范围 | 对于编译 | 对于测试 | 对于运行时 | 案例 |
---|---|---|---|---|
compile | √ | √ | √ | fast-json |
test | × | √ | × | Junit |
provided | √ | √ | × | servlet |
runtime | × | √ | √ | JDBC驱动 |
-
compile,在编译、测试以及运行的时候都需要;默认是compile,可以将其打包成war包或者是jar包;
-
test,只需要在测试的时候发挥其作用即可,不需要在编译和运行时发生任何作用;不会达到war包;
-
provided,因为其他组件已经自带了,只是需要在编译和测试的时候来使用一下,运行的时候不需要来使用;不会达到war包,这就是在使用web项目的时候,打包运行部署无效的情况
-
runtime,这里就有点类似多态了,编译阶段是不知道运行哪个的,但是在运行和测试阶段知道是舍取哪一个;在进行测试和运行的时候,JDBC需要连接到数据库来获取得到数据进行测试。所以需要获取对应的信息
1.5、maven插件
Maven是一个核心引擎,提供了基本的项目处理能力和建设过程的管理,以及一系列的插件是用来执行实际建设任务。maven插件可以完成一些特定的功能。例如,集成jdk插件可以方便的修改项目的编译环境;集成tomcat插件后,无需安装tomcat服务器就可以运行tomcat进行项目的发布与测试。在pom.xml中通过plugin标签引入maven的功能插件。
1.5.1、JDK编译版本插件
<!--jdk编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
1.5.2、Tomcat7编译版本插件
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>82</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
注意: Maven的中央仓库中只有Tomcat7.X版本的插件,而之前我们使用的是8.X的版本,如果想使Tomcat8.X的插件可以去其他第三方仓库进行寻找,或者使用IDEA集成外部Tomcat8极其以上版本,进行项目的发布。
1.5.3、标签说明
参考文章:https://blog.csdn.net/qq_36779675/article/details/119002721
dependencyManagement一般是用在顶层的POM文件中,用来管理jar包的版本,子项目中就不用再指定版本号(只是声明依赖,并没有引入依赖)。
dependencies中的依赖都会自动引入,默认被所有子项目继承。
使用dependencyManagement更换版本只需要修改父POM中的版本即可。
如果子项目需要另一个版本号,只需要在dependencies中声明一个版本号,就会优先使用子POM的版本号。
2、jar包冲突解决方式
首先分析下jar包冲突是如何产生的?这里通过图形来进行演示:
因为引入了两个jar包:a.jar和b.jar。但是maven有个特性,就是将jar包依赖的jar包也会导入进来。
那么这个时候,就会导入引入的ab两个jar包中的cjar包也会被引入进来。
那么看看maven中默认的处理方式。有三种:遵循第一声明者优先原则、路径近者优先、直接排除法
2.1、第一声明有限原则
哪个jar包在靠上的位置,这个jar包就是先声明的,先声明的jar包下的依赖包,可以优先引入项目中。在pom.xml中引入如下坐标,分别是spring中不同的版本。
<?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>
<groupId>com.guang</groupId>
<artifactId>maven_day01_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!--导入相关依赖包-->
<dependencies>
<!--引入spring-context,它所以来的包都会导入进来-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
</dependencies>
</project>
在maven中来分析一下坐标之间的关系,从maven中的一个按钮:show dependenies中可以看到整个项目中的依赖关系。
首先可以看到spring-context这个jar包和spring-beans这个jar包共同的依赖:spring-core
但是因为spring-context这个依赖在spring-beans前先导入,那么默认使用的是spring-core是5.0.2版本的。
那么也就是说,如果共同依赖了的,谁放在前面,那么就先使用谁的依赖。
但是可以看到spring-context和spring-beans同时又都依赖了spring-beans这个依赖,那么从左边可以看到,spring-beans是4.2.4,这是怎么回事?看看下面这个。
2.2、路径优先原则
修改jar包,直接引入依赖spring-core
<!--导入相关依赖包-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--引入直接依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.8.RELEASE</version>
</dependency>
</dependencies>
此时优先引入的是直接依赖的引用
那么这里也来画个图分析一波:
因为spring-context和spring-beans同时又都依赖了spring-beans这个依赖,而spring-beans是4.2.4又是已经导入进来了,所以就直接使用了。
这叫路径优先原则
2.3、直接排除法
整合项目需要用到5的版本,引入4的版本,会不会出现异常(类没有找到,方法没有找到)
这种情况是经常出现的,所以这种解决方式是我们需要必备的。
当我们需要排除某个jar包的依赖时,在配置exclusions标签的时候,内部可以不写版本号。pom.xml依赖如下:
<!--导入相关依赖包-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
<!--直接排除-->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
依赖导入的jar包如下,没有添加exclusion之前:
添加exclusion之后,因为排除了4.2.4的版本spring-core的jar包
在哪个坐标下面进行排除,表示的就是将哪个版本进行排除。
真实项目中,出现1个项目存在多个同种jar包的时候,需要我们进行解决maven的jar包冲突问题
(否则将会出现异常:Class not found、Method not found等)
3、工程拆分
3.1、项目为什么拆分
对于单体项目来说,只需要依赖共同的依赖即可。但是对于多个项目来说,如果有共同的功能,那么就应该将公共的模块单独拆分出来,组合成公共的模块,放在maven仓库中,以供其他模块来进行使用。
如下所示:
3.1、项目怎么拆分
3.1、项目拆分和聚合
对于单体项目来说,毫无区别。但是对于多模块项目来说,可能模块A依赖到模块B,模块C也需要依赖到模块B,那么对于开发人员来说,不可能将模块B分别复制到模块A、C中来,应该将模块B放置到本地仓库中来,然后打包的时候就会将模块B分别打包的模块A和模块C中来。
继承和聚合结构图:
聚合:父工程将子工程统一打包运行
父工程的作用:统一管理依赖以及聚合子工程
演示一个父工程的pom文件:
<?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>
<groupId>com.guang</groupId>
<artifactId>ssm_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!--
特殊属性定义,一般是版本号
-->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
<aspectjweaver.version>1.6.8</aspectjweaver.version>
<junit.version>4.12</junit.version>
<jsp-api.version>2.0</jsp-api.version>
<servlet-api.version>2.5</servlet-api.version>
<jstl.version>1.2</jstl.version>
<mybatis-spring.version>1.3.0</mybatis-spring.version>
<druid.version>1.0.9</druid.version>
<!--文件的编码格式-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<!--
jar包管理
dependencyManagement:并非导入依赖,而只是管理依赖(这样子工程可供选择)
-->
<dependencyManagement>
<!--引入依赖-->
<dependencies>
<!-- spring(切面) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectjweaver.version}</version>
</dependency>
<!-- spring(aop) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring包(核心)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--用于SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--用于数据库源相关操作-->
<!-- spring(整合jdbc) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring(事务) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Servlet相关API(可以使用Request、Response)-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency>
<!--jstl标签-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!--spring测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- log日志 start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--MyBatis集成Spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!--数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<!--插件-->
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<!--插件使用的相关配置-->
<configuration>
<!--端口号-->
<port>18081</port>
<!--写当前项目的名字(虚拟路径),如果写/,那么每次访问项目就不需要加项目名字了-->
<path>/</path>
<!--解决get请求乱码-->
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
如子类的pom文件:
<?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">
<parent>
<artifactId>ssm_parent</artifactId>
<groupId>com.guang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ssm_dao</artifactId>
<!--jar包-->
<packaging>jar</packaging>
<!--引入依赖-->
<dependencies>
<!--model的依赖-->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>ssm_model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<!--MyBatis集成Spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
<!--数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--SpringJdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
</project>
不再需要指定对应的版本号,即可直接使用了。