chaoz的杂货铺

生命有息、学无止境、折腾不止

0%

2021-java-maven

Maven代理设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>proxyuser</username>
<password>proxypass</password>
<host>proxy.host.net</host>
<port>80</port>
<nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>

<proxy>
<id>ss</id>
<active>true</active>
<protocol>socks5</protocol>
<username></username>
<password></password>
<host>127.0.0.1</host>
<port>8093</port>
<nonProxyHosts>127.0.0.1</nonProxyHosts>
</proxy>

id:代理的名称(随便设,XYZ也行)
active:表示该代理是否激活
protocol:代理协议,这个不用改 (socks5/http)
username:当代理需要认证时的用户名
password:当代理需要认证时的密码
host:代理的IP地址
port:代理的端口号
nonProxyHost:指定不需要使用代理的主机,可不设置。如果有多个,用 | 分隔
(P.S. 如果代理不需要用户认证,username 和 password 两个节点可注释掉)


命令行 export MAVEN_OPTS="-DsocksProxyHost=127.0.0.1 -DsocksProxyPort=1080"

maven插件

插件 plugings

什么是插件? maven提供的功能,用来执行清理、编译、测试、报告、打包的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
①. clean插件maven-clean-plugin:2.5
clean阶段是独立的一个阶段,功能就是清除工程目前下的target目录

②. resources插件maven-resources-plugin:2.6
resource插件的功能就是把项目需要的配置文件拷贝到指定的目当,默认是拷贝src\main\resources目录下的件到classes目录下

③. compile插件maven-compiler-plugin
compile插件执行时先调用resouces插件,功能就是把src\mainjava源码编译成字节码生成class文件,并把编译好的class文件输出到target\classes目录下

④. test测试插件
单元测试所用的compile和resources插件和主代码是相同的,但执行的目标不行,目标testCompile和testResources是把src\test\java下的代码编译成字节码输出到target\test-classes,同时把src\test\resources下的配置文件拷贝到target\test-classes

⑤. package打包插件maven-jar-plugin
这个插件是把class文件、配置文件打成一个jar(war或其它格式)包

⑥. deploy发布插件maven-install-plugin
发布插件的功能就是把构建好的artifact部署到本地仓库,还有一个deploy插件是将构建好的artifact部署到远程仓库

使用插件

maven实际上一个插件执行框架,所有的工作实际上都是通过插件完成,一个插件通常提供若干目标(goal),通过如下形式的命令执行插件目标:
mvn [plugin name]:[goal name]

例如可以通过编译插件compiler去编译目标,命令如下:
mvn compiler:compile

20210117205350

生命周期

maven是一种基于构建生命周期(build lifecycle)的项目构建工具, 也就是说一个项目的构建和发布是要经历几个过程的,目前主要包含三个过程:
clean
default
site
20210117210308

使用过mvn的就会发现,一个phase对应一个mvn的命令,比如当执行mvn compile命令时就是执行该phase之前的所有phase。
但是前言中说过mvn是通过插件来执行任务的,当执行mvn compile这个phase时,实际上是执行绑定在compile这个phase上的插件目标,由于compile这个phase默认绑定了compiler: compile(compiler插件的compile目标),因此执行mvn compile等于去执行了mvn compiler:compile

再例如:执行mvn package 实际上执行了插件mvn jar:jar(注意此处假设pom里配置了jar), 因为package这个phase默认绑定了jar:jar这个插件目标。

插件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<extensions>false</extensions>
<inherited>true</inherited>
<configuration>
<classifier>test</classifier>
</configuration>
<dependencies>...</dependencies>
<executions>...</executions>
</plugin>
</plugins>
</build>
</project>

一个<plugin></plugin>表示一个插件, <groupId>,<artifactId>,<version>都是引入必要配置。插件本质上托管在mvn仓库里。

<inherited>表示是否当前pom的子pom中继承这个插件配置,true表示子pom继承父pom这个插件配置,那么你就可以在子pom上通过mvn命令使用这个插件

<configuration>中包含了插件类实例化时用于初始化类成员信息

<dependencies>, 插件自身也会依赖外部包,<dependencies>中可以为插件指定特定的依赖包, 引入方式如下:

<executions>, 一个插件可能包含多个goal,<executions>中可以单独为某个goal指定配置,以及将goal绑定到某个phase。

executions包含的elements如下:
<executions>
<execution>
<!--需要在<executions>里面唯一的id-->
<id></id>
<!--列出需要特定去配置的所有goal-->
<goals>
<goal>run</goal>
</goals>
<!--将这些goal绑定到phase-->
<phase>verify</phase>
<!--指定子pom是否继承这些配置-->
<inherited>false</inherited>
<configuration>
<!--这里指定配置-->
</configuration>
</execution>
<execution>
...
</execution>
...
</executions>

比如下面就是一个几乎所有人都会用到的插件配置,compiler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <!--指定compiler插件版本信息-->
<configuration>
<!--插件实例化参数,这个参数是设置javac -source的值-->
<source>1.7</source>
<!--插件实例化参数,这个参数是设置javac -target的值-->
<target>1.7</target>
</configuration>
</plugin>

这里没有指定<executions>,因为compiler插件的目标compile默认被绑定到compile这个phase上了,
目标testCompile被绑定到了test-compile这个phase上了。
当然你可以显式指定,加入如下配置即可:
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>

scala插件scala-maven-plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<id>scala-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!--includes是一个数组,包含要编译的code-->
<includes>
<include>**/*.scala</include>
</includes>
</configuration>
</execution>
<execution>
<id>scala-test-compile</id>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

比较常用的两个goal:
compile 编译 scala code
testCompile 编译 test code

运行命令行:
mvn clean scala:compile compile

项目打包插件

maven-assembly-plugin

可用来打可发布可独立运行的jar包, 也就是说它可以将项目中所有依赖打进包。
mvn assembly:single

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<!--这个插件会输出多个包,原始包不包含任何依赖,
以及一个或者多个包含所有依赖的包,这些包以<descriptorRef>中的value为后缀。 这里可以配置n个<descriptorRef>,就会多生成n个包含所有依赖的包-->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<!--这里将single这个goal绑定在package这个phase上-->
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<!--<configuration>-->
<!--<archive>-->
<!--<manifest>-->
<!--<mainClass>me.test.sparktest.WordCount</mainClass>-->
<!--</manifest>-->
<!--</archive>-->
<!--</configuration>-->
</execution>
</executions>
</plugin>
</plugins>

去掉上面配置中<configuration></configuration>的注释,<mainClass>这个元素指定了MANIFEST.MF中的Main-Class。

maven-shade-plugin

和assembly插件一样它也可以将所有依赖打到包中,同时也可以打可执行的jar包。
运行命令mvn package(将shade绑定在package这个phase上,不然会出错)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<!-- put your configurations here -->
</configuration>
<executions>
<execution>
<!--将shade 这个goal绑定到package这个phase上-->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>

spring boot 插件

Spring Boot的 maven 插件能够以 maven 命令行的方式提供对 spring boot 应用打包和运行的支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.4.RELEASE</version>
<configuration>
<layout>WAR</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

20210117191122

repackage

绑定在package 这个phase上,可以为spring boot应用生成一个可执行的jar或war包。
以上面的plugin配置为例,运行mvn package会生成两个jar包,一个是原始jar包(也就是不使用这个插件时运行mvn package生成的jar包),一个是可执行的spring boot 应用的jar包。

1
2
3
下面是我的一个使用spring boot插件实例项目生成的两个war包(jar包类似):
webtest-1.0-SNAPSHOT.war 插件生成的war包
webtest-1.0-SNAPSHOT.war.original 这是原始的war包

原始包被重命名成以.original为后缀的包,改变后缀可使用如下配置方式:

1
2
3
4
5
6
7
8
9
10
11
<plugin>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<!--原始包的后缀将变成.exec-->
<classifier>exec</classifier>
</configuration>
</execution>
</plugin>

repackage生成的jar/war包会修改MANIFEST.MF文件,比如下面是我生成的war包中的MANIFEST.MF文件内容:

1
2
3
4
5
6
7
8
9
10
Manifest-Version: 1.0
Spring-Boot-Classes: WEB-INF/classes/
Built-By: eric
Build-Jdk: 1.7.0_71
Start-Class: me.test.webtest.WebMain
Created-By: Apache Maven 3.3.9
Spring-Boot-Lib: WEB-INF/lib/
Spring-Boot-Version: 1.5.4.RELEASE
Main-Class: org.springframework.boot.loader.WarLauncher
Archiver-Version: Plexus Archiver

我的测试项目main方法在WebMain这个类里面,但是可以看到生成的manifest文件中Main-Class是WarLaucher,还多了一个叫Start-Class的属性值是才是我的main方法所在类。
这是跟spring boot的启动方式有关系,运行该war包先启动WarLauncher会完成一些前期准备工作,完后最终会加载WebMain运行。打成jar也是一样的道理。

1
2
3
4
5
6
最终打包的的类型取决<layout>这个元素(第一个pom示例中有),可选值有如下:
WAR, 此时Main-Class如上
JAR, 此时Main-Class 是JarLauncher
ZIP, 包目录结构类似JAR,实时Main-Class是PropertiesLauncher
MODULE,只将当前module打进包,且不包含任何XXXLauncher
NONE, 和MODULE的区别是它会把当前的module的依赖也会打进包

run

在命令行运行mvn spring-boot:run可以启动spring boot应用(不过一般我们调试不都是直接在ide里点吗)。

1
2
3
4
5
6
7
8
可以通过如下配置给启动的jvm传递参数:
<plugin>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
</jvmArguments>
</configuration>
</plugin>

dev-tools

spring boot 1.3之后引入了dev-tools可以让你方便开发应用,在spring boot应用启动后,它监听资源文件的改变,或者重新编译生成class,有变化之后自动刷新(repackage是不会把dev-tools打进包的,所以生产环境dev-tool是不会起作用的)。

1
2
3
4
5
6
7
8
9
10
通过在pom中引入:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.5.4.RELEASE</version>
<!--指定optional为true可以避免被repackage打war时devtools也被打进war包-->
<optional>true</optional>
</dependency>
</dependencies>

可以通过设置 spring.devtools.remote.restart.enabled=false 这个java系统属性,是的dev-tools只在静态资源改变是才刷新。

start

stop

解决jar包冲突问题

出现的原因是:pom.xml中导入的jar包和maven自带的tomcat中的jar包发生了冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--放置的都是项目所要依赖的jar包-->
<!--provided的意思是编译时使用它,运行时不使用-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

-DarchetypeCatalog=internal

这个参数的意思是:
如果我们使用maven为我们提供好的骨架来创建maven工程,一般是要联网的.
为了在不联网的情况下我们可以正常创建工程,配了这样一个参数,只要我们之前联网下载过之前相关创建工程的插件,它就会从本地仓库找到对应插件,而不会联网下载

喜欢这篇文章?打赏一下作者吧!

欢迎关注我的其它发布渠道