1. 絮絮叨叨
-
做项目开发的时候,使用到了
kafka producer
,明明人家的编程示例只需要添加kafka-client
依赖 -
自己一旦运行起来以后,就开发报错,提示找不到
org/slf4j/LoggerFactory
-
然后,绕了一大圈,最终在添加以下maven后解决了问题:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency>
-
后来,同事告诉自己好好地去看看
kafka-client
的依赖传递,看看人家对slf4j的配置是怎样的。 -
自己回家发现,之前买的《maven实战》动都没动过,于是准备好好学习一下
-
毕竟自己接触了这么多Java项目,发现大部分都是使用maven去做依赖管理的,不学习以后只会耗费更多的时间在maven各种问题处理上 😂
2. 一些基础知识
2.1 关于pom文件
- maven项目的核心是
pom.xml
,这是maven项目实现项目构建、依赖管理、项目信息管理的关键。 - pom: Project Object Model,项目对象模型
以我自己的项目JianzhiOffer
为例,它最原始的pom文件如下:
- 第一行:xml头,指定了xml文档的版本和编码方式
- 第一个标签
<project>
,pom文件的根元素,里面地一些声明可以不用关注 <modelVersion>
标签,指定了pom的版本,目前固定为4.0.0
<groupId>
标签,一般包含了项目所在的组织或公司信息,例如,公司为sunrise的internet部门,则一般可以为com.sunrise.internet
<artifactId>
标签,当前maven项目在group中的唯一ID<version>
标签,项目版本号,一般起始版本号为1.0-SNAPSHOT
,后续不断更新为1.0
、1.1-SNAPSHOT
、1.1
等<?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>org.example</groupId> <artifactId>jianzhioffer</artifactId> <version>1.0-SNAPSHOT</version> </project>
2.2 其他知识
- 两种目录: maven项目在src目录下,应该包含
mian
和test
两个目录,前者用于存放主代码,后者用于存放测试代码。 - 代码的包名: 一般默认的前缀固定为
groupId.artifactId
,示例pom中的包名应该为org.example.jianzhioffer
。并且,main
和test
目录的包名应该一致 - 类名: 自己在主代码中创建了一个
HelloWorld
类,在测试代码中对应的类名为HelloWorldTest
- 方法名: 在
HelloWorld
类创建了一个sayHello()
方法,则在测试代码中,对应的单元测试方法为testSayHello()
3. 代码编译
3.1 实战
-
在主代码中创建
HelloWorld
类package org.example.jianzhioffer; public class HelloWorld { public String syaHello(String name) { return "Hello, " + name + "!"; } public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); String msg = helloWorld.syaHello("World"); System.out.println(msg); } }
-
使用如下命令进行代码编译:
mvn clean compile
-
从mvn的输出可以看出,maven先是
clean
了字节码文件所在的target/
目录,然后执行resources
任务(尚未使用到,暂不讨论), 最后执行compile任务
,在target/
目录生成了最新的字节码文件。[INFO] Scanning for projects... [INFO] [INFO] ----------------------< org.example:jianzhioffer >---------------------- [INFO] Building jianzhioffer 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ jianzhioffer --- [INFO] Deleting /Users/xxx/IdeaProjects/JianzhiOffer/target [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jianzhioffer --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ jianzhioffer --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 1 source file to /Users/xxx/IdeaProjects/JianzhiOffer/target/classes [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.682 s [INFO] Finished at: 2021-03-17T09:31:59+08:00 [INFO] ------------------------------------------------------------------------
3.2 编译报错:请使用 -source 7 或更高版本 ...
-
如果编译时,遇到以下错误提示说明需要配置maven的
compiler
插件,使其支持更高版本的jdk[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project test: Compilation failure [ERROR] /Users/xxx/IdeaProjects/Test/src/main/java/org/example/test/queue/Main.java:[8,69] -source 1.5 中不支持 diamond 运算符 [ERROR] (请使用 -source 7 或更高版本以启用 diamond 运算符)
-
解决办法: 在pom中添加以下信息
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
4. 代码测试
- 代码测试,主要是指单元测试
- 作为一个程序员,本人觉得单元测试是必须的,在单元测试中去尽可能多地覆盖各种情况,可以有效减少集成测试时的bug数,提高代码质量
4.1 添加junit
依赖
-
本人选择使用
junit
进行单元测试,因此在pom文件中添加了junit
的依赖。<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
-
<dependencies>
是所有依赖的根目录,<dependency>
为具体的依赖 -
<scope>
:指定了依赖的作用范围- 这里指定的是
test
,表明该依赖只能在测试代码中使用,不能在主代码中使用。 - 也就是说,不能在主代码中,以
import
的形式引用junit
任何代码。
- 这里指定的是
-
如果不明确指定
<scope>
,则默认为compile
,在主代码和测试代码中都可以使用该依赖。
4.2 单元测试的代码
- 在测试代码中,创建了对应的测试类,并编写好的
sayHello()
方法进行单元测试。 - 使用
@Test
注解,表明这是一个测试方法,执行maven的test
命令时,会自动执行该方法package org.example.jianzhioffer; import org.junit.Assert; import org.junit.Test; public class HelloWorldTest { @Test public void testSayHello() { HelloWorld helloWorld = new HelloWorld(); String msg = helloWorld.syaHello("lucy"); Assert.assertEquals("Hello, lucy!", msg); } }
4.3 执行单元测试
-
使用如下命令执行单元测试
mvn clean test
-
从输出可以看出,maven的执行顺序为:
clean --> resources: resources --> compile: compile --> resources: testResouerces --> compile: testCompile --> test
-
最终的输出可以看出,此次测试的执行情况:
------------------------------------------------------- T E S T S ------------------------------------------------------- Running org.example.jianzhioffer.HelloWorldTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.061 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
5. 代码打包与安装
5.1 mvn package
-
我们编写程序,可能大部分时候只是要求编程的IDE(如idea)能简单执行就ok了
-
但是,总有一些时候,你有类似这样的需求:你本地编写的代码需要打包成
jar
文件,放到服务器上运行。 -
这时候,maven的打包功能就派上用场了,只需要如下命令就可以轻松完成项目的打包:
mvn clean package
-
由于没有在pom文件中指定打包类型,默认会将项目打包成
jar
文件 -
完成打包后,可以在
target/
目录看到对应的jar。其命名由artifactId
个version
共同构成
-
提示: 用户可以自己通过输出命令,分析maven打包时执行的任务顺序。
5.2 mvn install
-
现在我们已经得到了项目的
jar
文件,如果想要在其他项目使用该文件,需要将其拷贝到对应的项目中才能生效 -
如果想要其他项目直接使用这个
jar
,需要将其安装到本地仓库 -
使用如下命令完成
jar
的安装mvn clean install
-
通过输出我们可以发现,maven已经将
jar
安装到了我们的本地仓库[INFO] Installing /Users/xxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT.jar to /Users/xxx/repo/org/example/jianzhioffer/1.0-SNAPSHOT/jianzhioffer-1.0-SNAPSHOT.jar [INFO] Installing /Users/xxx/IdeaProjects/JianzhiOffer/pom.xml to /Users/xxx/repo/org/example/jianzhioffer/1.0-SNAPSHOT/jianzhioffer-1.0-SNAPSHOT.pom
6. 如何让jar变得可运行?
-
其实啊,我一直都有一个疑问,我这个
jar
,能像在idea中一样,直接运行main方法吗? -
如果不能,那我拿他有何用,因为我就是想把它放到服务器上去执行的 😂
-
通过执行如下命令发现,好像目前的
jar
确实不支持 😂java -jar jianzhioffer-1.0-SNAPSHOT.jar
-
执行上述命令,被告知没有主清单属性:
jianzhioffer-1.0-SNAPSHOT.jar中没有主清单属性
-
其实,我们解压缩
jar
,找到META-INF/MANIFEST.MF文件,或发现其中确实没有Main-Class
这一行数据。 -
这时,需要借助
maven-shade-plugin
,去指定Main-Class
,才能在执行jar
时,自动执行main方法。 -
在pom文件中添加以下内容:
最重要的是,要在<mainClass>
标签中,指定main方法所在的类<build> <plugins> <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>org.example.jianzhioffer.HelloWorld</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
-
再次执行
install
命令,发现target/
目录下出现了两个jar
。前缀为origin
的jar
,是之前打包的jar
-
执行最新版本的jar,发现能正确找到main方法并执行
7. 总结
- 从初始的学习来看,maven在编译、测试、打包、安装上都非常地方便,通过添加对应的标签,可以实现依赖添加、指定main方法所在的类等。
<dependency>
中的<groupId>
、<artifactId>
和<version>
就像坐标的x、y、z
,通过指定这两个属性,可以轻松的找到对应的jar。这时,而具体使用哪个版本的jar可以通过<version>
去指定。