一,分模块开发与设计
分模块开发意义:将原始模块按照功能拆分成若干个子模块,方便模块间的相互调用,接口共享
新建两个模块,一个是总模块,负责调用其他模块,一个子模块,包含了domain:
- 在子模块Maven_pojo修改pom文件,只留下模块本身信息:
<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/maven-v4_0_0.xsd">
<parent>
<artifactId>Maven_ssm</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId> <artifactId>Maven_pojo</artifactId> <version>1.0-SNAPSHOT</version>
</project>
- 总模块Maven01_ssm中引入子模块依赖:
<!-- 依赖domain-->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>Maven_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 还有很重要的一步,要把依赖的子模块打包到本地仓库:
如果报错:不再支持源选项 5。请使用 7 或更高版本。
pom请加上:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
报错:Failed to start component [StandardEngine[Tomcat]
8月 21, 2023 6:47:09 下午 org.apache.catalina.core.ContainerBase startInternal
严重: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:335)
at org.apache.tomcat.maven.plugin.tomcat7.run.AbstractRunMojo.startContainer(AbstractRunMojo.java:1091)
at org.apache.tomcat.maven.plugin.tomcat7.run.AbstractRunMojo.execute(AbstractRunMojo.java:512)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 7 more
二,依赖管理
依赖传递:依赖具有传递性
- 直接依赖:在当前项目中通过依赖配置建立的依赖关系
- 间接依赖: 被资源的资源如果依赖其他资源,当前项目间接依赖其他资源
依赖传递冲突问题
- 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
- 声明优先: 当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
- 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
4.11覆盖4.12生效
可以点击maven插件的这个俺妞妞查看当前模块依赖分析图:
可选依赖(不透明)
有时候为了隐藏模块的依赖,可以使用option标签标记当前依赖是否向后传递:
<dependency>
<groupId>org.example</groupId>
<artifactId>maven01_domain</artifactId>
<version>1.0-SNAPSHOT</version>
<optional>true</optional>
</dependency>
表示maven01_domain依赖项不再向上级默哀快传递:
添加option之前:
之后:
可以看到domain模块被隐藏了,并且ssm模块无法使用domain模块里面的方法和对象了
排除依赖(不需要)
- 当用了别人的依赖,想要隐藏掉或者排除掉其中的间接依赖,这时候无法再向其中加入option标签,可以使用排除依赖
- 注:被排除的资源无需指定版本—不需要
- 指排除掉间接依赖,比如要排除dao模块里面的间接以来log4j,使用exclusion标签:
三,聚合与继承
聚合
- 聚合:将多个模块组织成一个整体,同时进行项目构建的过程称为聚合
- 聚合工程:通常是一个不具有业务功能的“空”工程(有且仅有一个pom文件)
- 作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建
- 当工程中某个模块发生更新(变更)时,必须保障工程中与已更新模块关联的模块同步更新,此时可以使用聚合工程来解决批量模块同步构建的问题
- 创建Maven模块,设置打包类型为pom
<packaging>pom</packaging>
- 设置当前聚合工程所包含的子模块名称:
<modules>
<module>../../Maven_ssm/maven01_domain</module>
<module>../../Maven_ssm/maven02_dao</module>
<module>../../Maven_ssm/mavenSSM</module>
</modules>
- 执行聚合工程的compile操作:
[INFO] maven01_domain ..................................... SUCCESS [ 0.674 s]
[INFO] maven02_dao ........................................ SUCCESS [ 0.029 s]
[INFO] mavenSSM Maven Webapp .............................. SUCCESS [ 0.094 s]
[INFO] maven00_parent ..................................... SUCCESS [ 0.001 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.893 s
[INFO] Finished at: 2023-08-22T14:32:28+08:00
[INFO] ------------------------------------------------------------------------
继承
- 概念:继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承
- 作用:简化配置,减少版本冲突
子工程加上继承信息:
<parent>
<groupId>org.example</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>
然后将所有子工程的通用配置提取到父工程,比如依赖坐标信息,然后刷新maven可以看到子工程也有了这些坐标:
继承管理可以实现父工程修改依赖版本等信息,子工程批量跟着变得效果
有些依赖或者配置子工程不一定全都要,可以在父工程中使用<dependencyManagement>标签:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
这样在子工程中使用这些依赖时候可以不写版本信息:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
聚合与继承的区别
作用
- 聚合用于快速构建项目
- 继承用于快速配置
相同点:
- 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
- 聚合与继承均属于设计型模块,并无实际的模块内容
不同点:
- 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
- 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
四,属性管理
定义属性:
<properties>
<spring.version>5.2.10.RELEAS</spring.version>
</properties>
使用属性:
<dependency>
<version>${spring.version}</version>
</dependency>
在resources文件中读取pom文件定义的属性
设置jdbc.properties:
jdbc.url=${jdbc.url}
然后再父工程pom中:
<properties>
<jdbc.url>jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false</jdbc.url>
</properties>
<build>
<resources>
<!--设置properties标签信息可以被读取的文件-->
<resource>
<directory>../maven_02_ssm/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
然后刷新maven,可以看到左边目录结构发生了调整:
可以看到,父工程可以直接访问子工程的resources资源文件了
如果需要所有的子项目的resources都可以使用父工程定义的属性,可以这样写:
<build>
<resources>
<!--设置properties标签信息可以被读取的文件-->
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
${project.basedir}称为maven内置属性:
版本管理
- 工程版本
- SNAPSHOT (快照版本)
- 项目开发过程中临时输出的版本,称为快照版本
- 快照版本会随着开发的进展不断更新
- RELEASE (发布版本)
- 项目开发到进入阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构件文件是稳定的,即便进行功能的后续开发,也不会改变当前发布版本内容,这和版本称为发布版本
- SNAPSHOT (快照版本)
- 发布版本
- alpha版
- beta版
- 纯数字版(3.1.2)
五,多环境配置与应用
maven提供配置多种环境的设定,帮助开发者使用过程中快速切换环境
pom文件中加入:
<!-- 配置多环境-->
<profiles>
<profile>
<id>env_dep</id>
<properties>
<jdbc.url>jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false</jdbc.url>
</properties>
</profile>
<profile>
<id>env_test</id>
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/spring_db?useSSL=false</jdbc.url>
</properties>
</profile>
<profile>
<id>env_produce</id>
<properties>
<jdbc.url>jdbc:mysql://127.2.2.1:3306/spring_db?useSSL=false</jdbc.url>
</properties>
<activation>
<!-- 默认启动环境-->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
表示配置了三个环境,其中第三个生产环境是默认项目启动环境,编译,可以看到生成的目标文件的jdbc.properties文件的url、变了:
jdbc.url=jdbc:mysql://127.2.2.1:3306/spring_db?useSSL=false
使用maveninstall时,可以手动改指定环境:
mvn install -P env_test
跳过测试
maven install时默认会执行测试,有时不需要测试,需要跳过,应用场景:
- 功能更新中并且没有开发完毕
- 快速打包
方法:
- 直接点击maven插件按钮:
- 还可以直接在pom文件中配置跳过测试,首先需要找到测试的插件,执行打包package操作,找到测试插件:
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven_02_ssm ---
[INFO] No tests to run.
pom文件配置:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
还可以设置部分测试类跳过测试:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>false</skipTests> <excludes> <exclude>**/BookServiceImplTest.java</exclude> </excludes>
</configuration>
</plugin>
- 指令跳过测试:
mvn package -D skipTests
六,私服
1,私服简介
- 私服是一台独立的服务器,用于解决团队内部的资源共享与资源同步问题
- 流行的私服Nexus:Sonatype公司的一款maven私服产品
nexus使用:
1,打开目录:D:\Program Files (x86)\Nexus\nexus-3.59.0-01-win64\nexus-3.59.0-01\bin
2,cmd,输入:nexus.exe /run nexus
这个启动一次比较慢,建议启动后cmd窗口就别关了
3,浏览器访问localhost:8081 登录:
按照提示找到密码:9edc0708-227d-4046-8634-xxxxxxxxxx
按照步骤设置好基础配置:
- 修改基础配置信息:
- 安装路径下etc目录中nexus-default.properties文件保存有nexus基础配置信息,例如默认访问端口
- 修改服务器运行配置信息:
- 安装路径下bin目录中nexus.vmoptions文件保存有nexus服务器启动对应的配置信息,例如默认占用内存空间
2,私服仓库分类
默认情况下模块包都是在maven本地仓库中,安装私服后,可以放在私服仓库中,其他人可以在这个私服仓库中拿
3,私服资源上传与下载
以上配置需要在maven的conf下的setteings.xml文件中配置:
打开后,找到server标签,复制一段出来,放在server标签内:
可以看到需要仓库名,打开nexus,点击齿轮,创建仓库:
命名为:
表示创建一个宿主仓库,注意,version-policy千万别选错,否则最后的deploy项目会报错400:400 Repository version policy: RELEASE does not allow version。
翻到最底下点创建
重复上面的步骤,在创建一个itheima-release仓库,类型选择release,version-policy选release
接下来在xml中填入server名称:
<!-- 配置访问私服的权限 -->
<server>
<id>itheima-snapshot</id>
<username>admin</username>
<password>320320</password>
</server>
<server>
<id>itheima-release</id>
<username>admin</username>
<password>320320</password>
</server>
然后需要配url映射,在xml文件中找到mirrors:
复制一个模板出来:
<!-- 私服访问路径 -->
<mirror>
<id>mirrorId</id>
<mirrorOf>repositoryId</mirrorOf>
<url>http://my.repository.com/repo/path</url>
</mirror>
需要填写私服id,打开
可以看到刚才创建的不在所管辖的仓库中,将左边俩拖过去:
记得点击save
然后将maven-public粘贴到id中去,mirrorof填*,然后填上url,完整如下:
<!-- 私服访问路径 -->
<mirror>
<id>maven-public</id>
<mirrorOf>*</mirrorOf>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
保存关闭xml文件
最后还需要配置每个工程打包到哪个私服仓库中,打开工程pom文件,加入:
<distributionManagement>
<!-- 配置正式版发布的仓库(非必要)-->
<repository>
<id>itheima-release</id>
<url>http://localhost:8081/repository/itheima-release/</url>
</repository>
<!-- 配置快照版发布的仓库(非必要)-->
<snapshotRepository>
<id>itheima-snapshot</id>
<url>http://localhost:8081/repository/itheima-snapshot/</url>
</snapshotRepository>
</distributionManagement>
接下来测试将工程打包放到私服,install是打包放在本地,deploy是上传到私服
打包deploy之前还需要做一件事,每个模块的pom都需要有<distributionManagement>标签,没有的话会报错,所以需要给每个子模块都加上这个标签,一种妥善的方式是父模块协商,子模块继承,就需要给每个子模块加上继承parent标签:
<parent>
<groupId>org.example</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>
最后,就可以执行deploy操作了,静等BUILD SUCCESS:
[INFO] maven_01_parent .................................... SUCCESS [ 1.191 s]
[INFO] maven_03_pojo ...................................... SUCCESS [ 2.035 s]
[INFO] maven_04_dao ....................................... SUCCESS [ 0.543 s]
[INFO] maven_02_ssm Maven Webapp .......................... SUCCESS [ 3.550 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.399 s
[INFO] Finished at: 2023-08-24T14:10:17+08:00
[INFO] ------------------------------------------------------------------------
Process finished with exit code 0
查看发布成功效果:
如果你的项目pom的version配的snapshot的话,就只会发布到snapshot仓库,如果是release就会发布到release仓库中去
报错:400 Repository version policy: RELEASE does not allow version
背景:将项目打包到nexus私服仓库中报错
出错代码:
<distributionManagement>
<!-- 配置正式版发布的仓库(非必要)-->
<repository>
<id>itheima-release</id>
<url>http://localhost:8081/repository/itheima-release/</url>
</repository>
<!-- 配置快照版发布的仓库(非必要)-->
<snapshotRepository>
<id>itheima-snapshot</id>
<url>http://localhost:8081/repository/itheima-snapshot/</url>
</snapshotRepository>
</distributionManagement>
原因:
1,要么是你创建仓库时version-policy选错了,snapshot仓库的version-policy选成了release等
2,要么是xml的distributionManagement填岔了