# Maven # Maven的Project管理 ## optional元素 - optional元素设置为true表示何意?optional是Maven依赖jar时的一个选项,表示该依赖是可选的,项目之间依赖不传递。不设置optional(默认)或者optional是false,表示传递依赖。 - 这里假设有两个项目A和B,其中A为父项目,B为子项目。当父项目添加junit依赖时,并未添加optional选项,也就是默认的optional元素的值为false。此时,子项目依赖父项目。 - 父項目A ```pom= <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> ``` - 子項目B ```pom= <dependencies> <dependency> <grouiesId>A</groupId> <artifactId>A</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> ``` - 父项目并未设置optional元素为true,那么便具有依赖传递性。此时,子项目B中会直接引入父项目A中引入的Junit的jar包。也就是说B项目打包时,jar/war包中会包含junit的jar包。 ## scope元素 - scope元素主要用来控制依赖的使用范围,指定当前包的依赖范围和依赖的传递性,也就是哪些依赖在哪些classpath中可用。常见的可选值有:compile, provided, runtime, test, system等。 ### compile - 默认值。compile表示对应依赖会参与当前项目的编译、测试、运行等。打包时通常会包含该依赖,部署时会打包到lib目录下。 ### test - 只有在單元測試時會用到,發佈程式時並不會用到,所以不會被打包 - 最常见的使用就是单元测试类了。 ```pom= <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> ``` ### runntime - 在编译环境下不会被使用,适用于运行和测试环节,發佈程式時須要一併打包。比如编译时只需要JDBC API的jar,而只有运行时才需要JDBC驱动实现。 - JDBC API的jar在JRE Syetem Library(由JDK提供)可以找到,就是java.sql。 - [Java JDBC API](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) - JDBC驱动实现 ```pom= <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> <scope>runtime</scope> </dependency> ``` ### provided - 仅在编译和测试阶段生效,不会被打包,也不具有传递性。 ### system - system范围依赖与provided类似,不过依赖项不会从maven仓库获取,而需要从本地文件系统提供。使用时,一定要配合systemPath属性。不推荐使用,尽量从Maven库中引用依赖。 ```pom= <dependency> <groupId>sun.jdk</groupId> <artifactId>tools</artifactId> <version>1.5.0</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> ``` ### import - 它只使用在`<dependencyManagement>`中,表示从其它的pom中导入dependency的配置。 - 大家在做SpringBoot应用的时候,都会有如下代码: ```pom= <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> ``` - 继承一个父模块,然后再引入相应的依赖。假如说,我不想继承,或者我想继承多个,怎么做? - Maven的继承和Java的继承一样,是无法实现多重继承的。 - 你可以把dependencyManagement放到单独的专门用来管理依赖的pom中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。例如可以写这样一个用于依赖管理的pom: ```pom= <project> <modelVersion>4.0.0</modelVersion> <groupId>com.test.sample</groupId> <artifactId>base-parent1</artifactId> <packaging>pom</packaging> <version>1.0.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies> </dependencyManagement> </project> ``` - 然后就可以通过非继承的方式来引入这段依赖管理配置 ```pom= <dependencyManagement> <dependencies> <dependency> <groupId>com.test.sample</groupId> <artifactid>base-parent1</artifactId> <version>1.0.0-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> </dependency> </dependencies> ``` - 如何解决一開始討論的SpringBoot的继承问题? ```pom= <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> ``` ## dependencyManagement - 在父項目中 ```pom= <dependencyManagement> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connectoer-java</artifactId> <version>5.1.44</version> </dependency> </dependencies> </dependencyManagement> ``` - 在子項目中只需要` <groupId>`和` <artifactId>`即可,如 ```pom= <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connectoer-java</artifactId> </dependency> </dependencies> ``` - 使用dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改。如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。 - 与dependencies区别: - Dependencies相对于dependencyManagement,所有生命在dependencies里的依赖都会自动引入,并默认被所有的子项目继承。 - dependencyManagement里只是声明依赖,并不自动实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。 # 例子 - 以cub-boot為例 - 我們的專案引入cub-boot ```pom= <groupId>com.example</groupId> <artifactId>checkId</artifactId> <version>0.0.1-SNAPSHOT</version> <name>checkId</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <parent> <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot</artifactId> <version>1.1.2-RELEASE</version> </parent> ``` - cub-boot中已經寫過的dependency,我們專案的pom就不需要再寫了,比如cub-boot-autoconfigure。 - cub-boot - cub-boot-dependencies是用來做依賴的版本管控,所以在cub-boot裡看到的依賴也都不用寫版本號。 ```pom= <name>Chris</name> <artifactId>cub-boot</artifactId> <packaging>pom</packaging> <parent> <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot-dependencies</artifactId> <version>1.1.2-RELEASE</version> <relativePath /> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot-autoconfigure</artifactId> </dependency> ..... </dependencies> ``` - cub-boot-autoconfigure ```pom= <parent> <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot-dependencies</artifactId> <version>1.1.2-RELEASE</version> <relativePath /> </parent> <artifactId>cub-boot-autoconfigure</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> <scope>provided</scope> </dependency> ..... </dependencies> ``` - 若引入的dependency的scope是provided,那表示只有在編譯和測試時會被使用,不會被打包,也不具有傳遞性。(因為不會被打包)所以在cub-boot-autoconfigure打包成jar後,lib裡面不會包含那些provided的依賴,(因為不具有傳遞性)我們的checkId專案打包之後,lib裡也不會有cub-boot-autoconfigure中scope是provided的依賴。 - 如何看到專案打包後,包含的依賴? - 對checkId專案右建Run -> Maven Install -> target資料夾找到已打包好的專案checkId-0.0.1-SNAPSHOT.jar -> 將該jar檔複製一份到桌面並解壓縮 -> checkId-0.0.1-SNAPSHOT\BOOT-INF\lib中就可以看到包含了哪些依賴 - cub-boot-dependencies ```pom= <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot-dependencies</artifactId> <packaging>pom</packaging> <version>1.1.2-RELEASE</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.6.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <swagger.version>2.9.2</swagger.version> ....... </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>com.cathaybank.boot</groupId> <artifactId>cub-boot-autoconfigure</artifactId> <version>${cub.boot.version}</version> </dependency> ...... </dependencies> </dependencyManagement> ``` # 參考 [Maven中optional和scope元素的使用,你弄明白了?](https://cloud.tencent.com/developer/article/1756145) [Maven教學](https://kentyeh.github.io/mavenStartup/index.html) [Maven依赖中的Scope详解](https://segmentfault.com/a/1190000038594247) [Maven中dependencyManagement作用说明](https://blog.csdn.net/vtopqx/article/details/79034835) ###### tags: `Maven`