maven系列--依赖
dependency
依赖写法
问题引出
如果Maven项目要引入某个依赖,需要三要素:groupId、artifactId和version,例如:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
步骤
1. 进入maven仓库网站:http://mvnrepository.com/
2. 检索关键字spring-webmvc
3.找到最匹配的结果
4.点击想要的版本(version列中的链接)
5.上一步结束后,就会出现Maven、Grable等依赖的写法
dependency其他项
systemPath
当maven依赖本地而非repository中的jar包,sytemPath指明本地jar包路径,例如:
<dependency> <groupid>org.hamcrest</groupid> <artifactid>hamcrest-core</artifactid> <version>1.5</version> <scope>system</scope> <systempath>${basedir}/WebContent/WEB-INF/lib/hamcrest-core-1.3.jar</systempath> </dependency>
type
引入某一个依赖时,必须指定type,这是因为用于匹配dependency引用和dependencyManagement部分的最小信息集实际上是{groupId,artifactId,type,classifier}。
在很多情况下,这些依赖关系将引用没有classifier的jar依赖。这允许我们将标识设置为{groupId,artifactId},因为type的默认值是jar,并且默认classifier为null。
type的值一般有jar、war、pom等,声明引入的依赖的类型。
classifier
classifier它表示在相同版本下针对不同的环境或者jdk使用的jar,如果配置了这个元素,则会将这个元素名在加在最后来查找相应的jar,例如:
<classifier>jdk17</classifier> <classifier>jdk18</classifier>
Classifier可能是最容易被忽略的Maven特性,但它确实非常重要,我们也需要它来帮助规划坐标。
设想这样一个情况,有一个jar项目,就说是 dog-cli-1.0.jar 吧,运行它用户就能在命令行上画一只小狗出来。现在用户的要求是希望你能提供一个zip包,里面不仅包含这个可运行的jar,还得包含源代码和文档,换句话说,这是比较正式的分发包。这个文件名应该是怎样的呢?dog-cli-1.0.zip?不够清楚,仅仅从扩展名很难分辨什么是Maven默认生成的构件,什么是额外配置生成分发包。如果能是dog-cli-1.0-dist.zip就最好了。这里的dist就是classifier,默认Maven只生成一个构件,我们称之为主构件,那当我们希望Maven生成其他附属构件的时候,就能用上classifier。常见的classifier还有如dog-cli-1.0-sources.jar表示源码包,dog-cli-1.0-javadoc.jar表示JavaDoc包等等。
optional
指依赖是否可选,默认为false,即子项目默认都继承。若设置为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 。
依赖原则
最短路径原则
A -> B -> C -> D(V1)
F -> G -> D(V2)
假设test依赖于D,这时maven会采用最短路径原则,选择V2版本的D。
因为V1版本的D是由A包间接依赖的,整个依赖路径长度为3,而V2版本的D是由F包间接依赖的,整个依赖路径长度为2。
优先声明原则
A -> B -> D(V1)
F -> G -> D(V2)
如果两个jar包版本路径深度相同,maven会根据pom文件声明的顺序加载,使用优先声明的版本
直引覆盖原则
多次直引不同版本的jar时,使用最后声明的版本。
如果再pom文件中,同时引用了如上两个版本,则会使用4.3.20.RELEASE版本
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.17.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.20.RELEASE</version>
</dependency>
依赖范围
范围(scope)定义了类包在项目的使用阶段。项目阶段包括: 编译,运行,测试和发布(打包)。
项 |
说明 |
compile |
缺省值,表示当前依赖参与项目的所有阶段(编译,运行,测试和发布),属于强依赖。 |
provided |
参与编译,运行,测试,不参与发布。 类似compile,区别在于不参与发布(打包阶段进行了exclude操作)。 此依赖的发布由运行的环境来提供,比如tomcat或者基础类库等等。 |
system |
使用上与provided相同。 不同之处:该依赖从本地文件系统中提取(需要显式提供包含依赖的jar),而不是从maven仓库中提取,其会参照systemPath的属性进行提取依赖。 |
test |
只在测试时使用,参与编译、运行、测试。不会随项目发布。 |
runtime |
只在运行时使用。参与运行和测试阶段。 一般这种类库都是接口与实现相分离的类库,比如JDBC类库,在编译之时仅依赖相关的接口,在具体的运行之时,才需要具体的mysql、oracle等等数据的驱动程序。 |
import |
maven2.0.9版本后出的属性,import只能在dependencyManagement的中使用,能解决maven单继承问题,import依赖关系实际上并不参与限制依赖关系的传递性。 |
问题解决示例
SpringBoot代码上加了测试
HelloApplicationTests.java(所在路径:src/main/java/com.example.rabbitmqhello)
package com.example.rabbitmqhello;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = HelloApplication.class)
public class HelloApplicationTests{
@Autowired
private Sender sender;
@Test
public void hello() throws Exception {
sender.send();
}
}
发现@RunWith(SpringJUnit4ClassRunner.class)被标红,鼠标放上去提示:Cannot resolve symbol "SpringJUnit4ClassRunner"
原因
测试类一般是放在src/test/java,而不是放在src/main/java下。maven在编译的时候,src/main/java下是不引用<scope>test</scope>的jar,而编译src/test/java下的测试这会引用<scope>test</scope>的jar。
本处在src/main/java中使用测试注解,但不会引用到相关类,就会找不到SpringJUnitClassRunner.class。
解决方法
法一:将测试包的<scope>test</scope>改为<scope>compile</scope>
法1:直接修改pom.xml
法2:File=> Project Structure=> Project Settings=> Modules=> 选中相应模块=> Dependencies=> 修改相应包为compile
法二:将代码所在文件夹属性设为test
法1:将代码放到src/test/java下
法2:将所在文件夹标记为Test:右键此文件夹=> Mark Directories As=> Test Sources Root
依赖的传递性与排除
依赖的传递性:A依赖B,B依赖C,A能否使用C呢?那要看B依赖C的范围是否是compile,如果是则可用,否则不可用。
a.可以传递的依赖不必在每个工程中都重复声明,在“最下面”的工程中依赖一次即可。
b.非compile范围的依赖不能传递,所以在各个工程模块中,如果有需要就得重复声明。如servlrt-api。
依赖的排除
依赖的排除:如果我们不想通过 A->B->C>D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉。
排除的原因一般有:1.依赖不够/不够稳定 2.与其他的包冲突(同名包)
示例:将 redis 的 lettuce依赖排除
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!--不依赖Redis的异步客户端lettuce -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
排除所有依赖
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
dependencyManagement
在Maven多模块的时候,管理依赖关系是非常重要的,各种依赖包冲突,查询问题起来非常复杂,于是就用到了<dependencyManagement>。
父模块:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块中只需要<groupId>和<artifactId>即可,如:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
说明:
使用dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
与dependencies区别:
1)Dependencies
所有声明在dependencies里的依赖都会自动引入,并默认被所有的子项目继承。2)dependencyManagement
只是声明依赖,并不自动实现引入,因此子项目需要显式声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
常用的项
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencies>
</dependencyManagement>
<dependencyManagement>
<dependencies>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencies>
</dependencyManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
引入第三方依赖
其他网址
maven 导入第三方包_qq_23476319的博客-CSDN博客_maven install 怎么引入大量的第三方包
法1 指定lib目录为编译参数
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <compilerArguments> <extdirs>${basedir}\src\main\webapp\WEB-INF\lib</extdirs> </compilerArguments> </configuration> </plugin>
法2 指定单个jar
<dependency> <!--if add it into the </dependencyManagement>, it does not work--> <groupId>test.search</groupId> <artifactId>binarySearch</artifactId> <version>1.0.3</version> <systemPath>${basedir}/tmp/binary_search.jar</systemPath> <scope>system</scope> </dependency>
注意:这种方式在打包生成可执行jar文件时,抓取不到该jar文件,即 MANIFEST.MF 文件中没有该jar文件的配置信息。
解决方法:maven-shade-plugin<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>netty_in_action.chapter_2_2.EchoServer</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
法3:将JAR包传入到MAVEN仓库服务器的 第3方仓库中
1. 可以通过 http://ip:8081/nexus 管理页面 上传到服务器
2. 通过命令行 上传JAR包
mvn install:install-file -DgroupId=org.jboss.cache -DartifactId=jbosscache-core -Dversion=3.2.7.GA -Dpackaging=jar -Dfile=D:\jbosscache-core-3.2.7.GA.jar
一些参数说明如下:
-DgroupId=远程仓库对应的DgroupId
-DartifactId= 远程仓库对应的 DartifactId
-Dversion=对应版本号
POM.XML中直接引入
<dependency> <groupId>com.gxhs.analysis2</groupId> <artifactId>netty-client-distributed</artifactId> <version>2.0</version> </dependency>
Jar转为pom.xml
其他网址
基于Maven中心库 通过Jar包生成Maven POM.xml的dependency_java,maven_贾小黑的博客-CSDN博客
将项目中的jar文件生成pom文件_Java_闵渭凯-CSDN博客
本程序会在控制台中输出依赖,例如:
<dependencies>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>XXX</groupId>
<artifactId>mysql-connector-java-bin</artifactId>
<version>5.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
所需包
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastJson</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
package com.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.dom4j.Element;
import org.dom4j.dom.DOMElement;
import org.jsoup.Jsoup;
import com.alibaba.fastjson.JSONObject;
public class Jar2Pom {
public static void main(String[] args) throws FileNotFoundException, IOException {
Element dependencies = new DOMElement("dependencies");
File dir = new File("E:\\my_project\\test\\src\\main\\lib"); //需生成pom.xml 文件的 lib路径
System.out.println("<dependencies>");
for (File jar : dir.listFiles()) {
JarInputStream jis = new JarInputStream(new FileInputStream(jar));
Manifest mainmanifest = jis.getManifest();
jis.close();
//其他网站方法都少这个判断,会抛出空指针异常
if(mainmanifest==null) {
continue;
}
String bundleName = mainmanifest.getMainAttributes().getValue("Bundle-Name");
String bundleVersion = mainmanifest.getMainAttributes().getValue("Bundle-Version");
Element ele = null;
StringBuffer sb = new StringBuffer(jar.getName());
if (bundleName != null) {
bundleName = bundleName.toLowerCase().replace(" ", "-");
sb.append(bundleName+"\t").append(bundleVersion);
ele = getDependices(bundleName, bundleVersion);
//System.out.println(sb.toString());
//System.out.println(ele.asXML());
}
if (ele == null || ele.elements().size() == 0) {
bundleName = "";
bundleVersion = "";
String[] ns = jar.getName().replace(".jar", "").split("-");
for (String s : ns) {
if (Character.isDigit(s.charAt(0))) {
bundleVersion += s + "-";
} else {
bundleName += s + "-";
}
}
if (bundleVersion.endsWith("-")) {
bundleVersion = bundleVersion.substring(0, bundleVersion.length() - 1);
}
if (bundleName.endsWith("-")) {
bundleName = bundleName.substring(0, bundleName.length() - 1);
}
ele = getDependices(bundleName, bundleVersion);
sb.setLength(0);
sb.append(bundleName+"\t").append(bundleVersion);
//System.out.println(ele.asXML());
}
ele = getDependices(bundleName, bundleVersion);
if (ele.elements().size() == 0) {
ele.add(new DOMElement("groupId").addText("XXX"));
ele.add(new DOMElement("artifactId").addText(bundleName));
ele.add(new DOMElement("version").addText(bundleVersion));
}
System.out.println("\t" + "<dependency>");
Iterator<DOMElement> iterator = ele.nodeIterator();
while(iterator.hasNext()){
System.out.println("\t\t" + iterator.next().asXML());
}
System.out.println("\t" + "</dependency>");
//System.out.println("\t"+ele.asXML());
//dependencies.add(ele);
}
//System.out.println(dependencies.asXML());
System.out.println("</dependencies>");
}
public static Element getDependices(String key, String ver) {
Element dependency = new DOMElement("dependency");
// 设置代理
// System.setProperty("http.proxyHost", "127.0.0.1");
// System.setProperty("http.proxyPort", "8090");
try {
String url = "http://search.maven.org/solrsearch/select?q=a%3A%22" +
key + "%22%20AND%20v%3A%22" + ver + "%22&rows=3&wt=json";
org.jsoup.nodes.Document doc = Jsoup.connect(url).ignoreContentType(true).timeout(30000).get();
String elem = doc.body().text();
JSONObject response = JSONObject.parseObject(elem).getJSONObject("response");
if (response.containsKey("docs") && response.getJSONArray("docs").size() > 0) {
JSONObject docJson = response.getJSONArray("docs").getJSONObject(0);
Element groupId = new DOMElement("groupId");
Element artifactId = new DOMElement("artifactId");
Element version = new DOMElement("version");
groupId.addText(docJson.getString("g"));
artifactId.addText(docJson.getString("a"));
version.addText(docJson.getString("v"));
dependency.add(groupId);
dependency.add(artifactId);
dependency.add(version);
}
} catch (Exception e) {
e.printStackTrace();
}
return dependency;
}
}
pom.xml生成Jar
其他网址:jar文件和pom.xml文件依赖之间的转换_Java_断橋殘雪的博客-CSDN博客
1:创建pom2jar.bat
内容如下
call mvn -f pom.xml dependency:copy-dependencies @pause
2.创建pom.xml
在此pom.xml中添加相应依赖即可
<?xml version="1.0"?>
<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>temp.download</groupId>
<artifactId>temp-download</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 需要下载Jar包,只需要在pom.xml文件中添加相应依赖-->
<!-- 示例 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>
</project>
3.将pom2jar.bat与pom.xml放到同一个文件夹
4.双击pom2jar.bat
jar包文件会下载在target/dependency/
上一篇: php图片处理函数简单例子
下一篇: PHP工程师的面试题【部分解答】