1. pom内容
pom文件一打开,有这么几个大块的分组:
(1)dependency
dependency内部通过groupId,artufactId以及version确定唯一的依赖
groupId: 组织的唯一标识。
artifactId: 项目的唯一标识。
version:项目的版本。
(2)properties
应该是自定义的属性值,为了在pom的其他地方引用这些properties
<properties>
<mysql.version>5.1.1</mysql.version>
</properties>
(3)编译插件plugin
2. spring-boot-maven-plugin
(1) 如果你的POM是继承spring-boot-starter-parent的话,只需要下面的指定就行。
<properties>
<!-- The main class to start by executing java -jar -->
<start-class>com.mycorp.starter.HelloWorldApplication</start-class>
</properties>
(2)如果你的POM不是继承spring-boot-starter-parent的话,需要下面的指定。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.5.RELEASE</version>
<configuration>
<mainClass>${start-class}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
上面这两种情况的原理,是由于你引入了<parent>,然后springboot的parent在build的子标签里面有pluginManagement,已经把springboot-maven-plugin这个插件的很多都写出来了,唯一就是引用了一个${start-class},所以你补上就行。
如果没继承这个parent,那么写出来的跟抄这个parent下面是一样的。
(这里又涉及到另一个只是,只要是pom里面的Maganement,无论是dependencyManagement还是pluginManagement,都是在父工程里面用的,在父工程里面用了之后,子工程直接继承,所以你多半不会自己去主动定义。)
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
- configuration:该插件所需要的特殊配置,在父子项目之间可以覆盖或合并
- executions:plugin 可以有多个目标,每一个目标都可以有一个分开的配置,甚至可以绑定一个 plugin 的目标到一个不同的阶段。executions 配置一个 plugin 的目标的 execution。一个 execution 有如下设置:
- id,唯一标识
- goals,要执行的插件的 goal(可以有多个),如 <goal>repackage</goal>
- phase,目标执行的阶段,具体值看Maven的生命周期列表
- inherited,该 execution 是否可被子项目继承
- configuration,该 execution 的其他配置参数
(execution里面的这几个子项,应该只有上三个有用。以及这些都是事先被定义好的流程,你写的这些都是在给别人的框架传配置。)
execution是一个执行任务,configuration是这个任务能用到的参数,有一些configuration是plugin用的,有一些是execution用的,反正都是框架定义好的参数,你只要传递就行了。
execution里面有用的只有一个goal,goal应该只会需要repackage模式,经过了这个repackage之后,打出来的包才有两个,一个是.original,一个是.jar,maven第一次打出来的包再次打包的时候变成了.original,然后第二次打包结果变成.jar。从体积上来计算,.original是几百k,源代码也是几百k,而.jar是几十兆,应该是一个胖包一个瘦包,再次打包的过程把所有的依赖都打进去了。
3. docker-maven-plugin
思路:首先知道根据dockerfile是怎么打包的,
这里开始解析dockerfile里面的每一句,
然后把dockerfile变成pom里面的<>。
(1) dockerfile内容
#父镜像
FROM java:8
#拷贝jar包
ADD scm.jar app.jar
#暴露接口
EXPOSE 8080
#启动容器的时候运行jar包
ENTRYPOINT [ "java", "-jar", "/app.jar" ]
如果真写起来dockerfile的话,上面应该就够用了。
dockerfile里面的四句话,父镜像,添加jar,运行jar,-p暴露端口。
(要调研的应该也就是Add和Entrypoint这两个有什么区别,或者不调研了)
Copy和Add用法好像一样的,都是Copy/Add + 要复制的jar + 别名
(2)使用dockefile结合插件
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--使用docker-maven-plugin插件-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<!--将插件绑定在某个phase执行,下面的这个execution发挥的作用就是把这个docker打包镜像的过程绑定到了maven-plugin上面去-->
<executions>
<execution>
<id>build-image</id>
<!--用户只需执行mvn package ,就会自动执行mvn docker:build-->
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!--指定生成的镜像名-->
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<!--指定标签-->
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<!-- 指定 Dockerfile 路径-->
<dockerDirectory>${project.basedir}</dockerDirectory>
<!--指定远程 docker api地址-->
<dockerHost>http://10.112.158.59:2375</dockerHost>
<!-- 这里是复制 jar 包到 docker 容器指定目录配置,相当于dockerfile里面的那句Add -->
<resources>
<resource>
<targetPath>/</targetPath>
<!--需要复制的jar 包所在的路径 此处配置的 即对应 target 目录,这个表达式你背下来就行了不用变-->
<directory>${project.build.directory}</directory>
<!-- 需要复制的 jar包 ,这里对应的是 Dockerfile中添加的文件名,也是背下来就行了 -->
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
(3) 完全使用pom文件
这个是结合上面的那一份代码,改动了其中的dockerfile的那一句,变成了另外三句(其中的copy语句是下面的resource)。
以及下面这份文档应该是可以直接复制的,除了中间有服务器地址和端口号两个之外感觉别的都不用变。
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!--使用docker-maven-plugin插件-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<!--将插件绑定在某个phase执行-->
<executions>
<execution>
<id>build-image</id>
<!--用户只需执行mvn package ,就会自动执行mvn docker:build-->
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 这里是生成dockerfile的,也就是不需要自己写dockerfile了,直接在这个pom里面定义!!!!流弊!!!
dockerfile里面的每一行在这里面都有一个标签名<>对应着-->
<!--指定生成的镜像名,这里注意docker生成文件的前缀,在上面要有一个properties来定义这个前缀-->
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<!--指定标签-->
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<!--指定远程 docker api地址(!!!这里要变化)-->
<dockerHost>http://10.112.158.59:2375</dockerHost>
<!-- 指定 Dockerfile 路径-->
<!-- <dockerDirectory>${project.basedir}</dockerDirectory>-->
<!-- 从这里开始是重点了-->
<baseImage>java:8</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<exposes>
<!--(!!!)这个暴露接口也要变化 -->
<expose>7050</expose>
</exposes>
<!-- 这里是复制 jar 包到 docker 容器指定目录配置 -->
<resources>
<resource>
<targetPath>/</targetPath>
<!--jar 包所在的路径 此处配置的 即对应 target 目录-->
<directory>${project.build.directory}</directory>
<!-- 需要包含的 jar包 ,这里对应的是 Dockerfile中添加的文件名 -->
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
(4) 生成镜像之后是要用下面的视图来启动容器的
至于这个视图启动容器看着就简单,就不写了。
4. maven
(1) maven项目结构
构建打包技术,发展历史是make -> ant -> maven -> gradle
maven工程中各目录结构含义也就是说现在的工程就是一个maven工程,所以现在的src、pom、resource什么的全都是由这个maven工程来决定的,这是maven的约定,让maven知道什么的东西放在哪里,然后可以自动化构建。、
(2)maven依赖
首先是依赖的排除,一定是一个很大的依赖,里面一堆二级子依赖,然后这里面的一堆想排除哪个哪个,在这个大依赖的标签下面写排除。
<dependency>
<exclusion>
然后是依赖冲突,如果对于一个依赖的好几个版本都声明了,两个原则。首先是路径最短的优先,你直接引用是要比在别的大包里面带进来要优先的;如果路径一样,先声明的优先,如果都是大包带进来的,那么排在上面的优先。
最后是统一管理依赖的版本。原理大概就是在pom里面的<properties>里面声明各种自定义属性,然后在下面引用dependency的时候,在version里面用${}来引用上面定义的属性。应该是应用于一个体系的框架内的所有引用,比如spring框架的很多东西,把这些所有与spring相关的引用版本保持一致。
(3) maven生命周期
- clean应该是删除target吧
- compile是把.java变成.class文件
- test是执行test文件夹里面的测试程序
- package是在target文件夹里面生成很多包括jar包在内的很多东西
- install是把jar包拷贝到本地的maven仓库,然后本机上的其他工程就能引用这个工程的依赖。
- deploy是把jar包拷贝到servlet里面运行,这个目前没啥用了,达到的效果是在本机上把程序跑起来,有一种愚蠢的启动办法,是把项目打包成jar包,然后把jar包拷贝到Tomcat里面去运行,deploy完成了这个功能,当然现在都能用Idea直接run就没必要了。
- site也是只能在服务器上执行的,用Shell命令mvn site xxxx什么的,所以没啥卵用。
所以总结,最终在idea上的mvn插件里面有用的仍然只有一个clean和package。
以及maven的常用命令,mvn开头的那几个Linux命令,完完全全就对应了上面的这几个指令,clean、test、package什么的。
(4) maven的坐标
跟上面的maven依赖联系起来。
- groupId:组织标识,一般为:公司网址的反写+项目名
- artifactId:项目名称,一般为:项目名-模块名
- version:版本号
所有的maven项目都要有上面的三个坐标,三个加起来就在仓库里面唯一确定了这个依赖。dependency引用的时候也是用这三个加起来就能指定到底引用哪一个项目,所以dependency下面有用的也是这三个。
(5)继承 <parent>
这个是为了在一个父工程里面统一管理依赖版本的。
用处就是在父工程里面定义一个<dependencyManagement>,在这里面定义各种<dependency>,写上版本号。
再之后在子工程里面继承这个parent,子工程里面再引用各种dependency的时候就可以不写版号了。
(这个parent不能给子工程引入依赖,只是对依赖版本version的统一管理)
(6)聚合 <module>
module这个,如果聚合起来了的话,从parent入口那里可以直接把所有的项目一键打包并且复制到本机的Tomcat,所有工程的一键部署吧(学了之后感觉没卵用)
(7)依赖作用范围<scope>
这个就是表示这个依赖会在哪里起作用,会不会进入最终的jar包吧,如果不配置默认是打进jar包的。
- compile,缺省值,适用于所有阶段,会打包进项目。
- provided,类似compile,期望JDK、容器或使用者会提供这个依赖。
- runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。
- test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
- system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
网友评论