1.何為依賴?
比如你是個男的,你要生孩子,呸呸呸...男的怎麼生孩子,所以你得依賴你老婆,不過也不一定咯,你也可以依賴其她妹子。
我們在平時的項目開發中也是同理,你需要依賴一些東西才能實現相應的功能,但相應的功能或許也可以依賴其它的東西實現,比如數據庫操作吧,你可以依賴hibernate,但你也可以通過mybatis來做。
這就是所謂的依賴關系咯。
以前我們需要手動的去找hibernate或者mybatis的jar包,系統拋異常我們還不知哪裡報錯,通過琢磨才明白沒有引入相應的jar包,然後就去找啊找,找到了然後引入到工程當中。在這裡我們就看到maven的好處了,它就是一個倉庫,倉庫裡面有各種各樣的包,想要什麼就在pom.xml中依賴一下就好了,就算倉庫中沒有的包也可以把它扔到倉庫中,想用的時候就依賴一下。
2.依賴的配置
1 <project> 2 <dependencies> 3 <dependency> 4 <groupId>junit</groupId> 5 <artifactId>junit</artifactId> 6 <version>3.8.1</version> 7 <type>...</type> 8 <scope>test</scope> 9 <optional>...</optional> 10 <exclusions> 11 <exclusion> 12 <groupId>...</groupId> 13 <artifactId>...</artifactId> 14 </exclusion> 15 </exclusions> 16 </dependency> 17 </dependencies> 18 </project>
根元素下project下的dependencies可以包含一個或者多個dependency元素,以聲明一個或者多個項目依賴。每個依賴可以包含的元素有:
groupId,artifactId和version:依賴的基本坐標,對於任何一個依賴來說,基本坐標是最重要的,Maven根據坐標才能找到需要的依賴。
type:依賴的類型,對應於項目坐標定義的packaging。大部分情況下,該元素不必聲明,其默認值是jar。
scope:依賴的范圍,後面會進行詳解。
optional:標記依賴是否可選。
exclusions:用來排除傳遞性依賴,後面會進行詳細介紹。
大部分依賴聲明只包含基本坐標,然而在一些特殊情況下,其他元素至關重要,我們來看看。
3.依賴范圍說明
由於不同的包在不同的地方用到,像junit我們只有在做測試的時候會用到這個包,在我們項目發布的時候,用不到這個包;還有servlet-api,在項目編譯的時候將會用到這個包,而項目發布的時候就不會用到這個包,因為一般容器已經自帶這個包,如果我們導入,有可能會出現沖突,所以maven引入了依賴范圍這個概念,即我們上面提到的scope來解決這個問題。Maven中有主要有以下這幾種依賴范圍:
1) test:指的是測試范圍有效,在編譯打包、運行時都不會使用這個依賴。例如:junit jar包。
2) compile:指的是編譯范圍有效,在編譯、測試、打包、運行時都會將依賴存儲進去。如果沒有指定,就會默認使用該依賴范圍。例如:hibernate jar包。
3) provided:在編譯和測試的過程有效,最後生成包時不會加入,運行時自然也沒效果。例如:servlet-api,因為servlet-api,tomcat等web服務器已經存在該jar包了,如果再打包可能會有沖突。
4) runtime:在測試、運行的時候依賴,在編譯的時候不依賴。例如:JDBC驅動,項目代碼只需要jdk提供的jdbc接口,只有在執行測試和運行項目的時候才需要實現jdbc的功能。
5) system:系統依賴范圍。該依賴范圍與provided所表示的依賴范圍一致,對於編譯和測試有效,但在運行時無效。只是使用system范圍依賴時必須通過systemPath元素顯式地指定依賴文件的路徑。由於此類依賴不是通過Maven倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此應該謹慎使用,systemPath元素可以引用環境變量。例如:
1 <dependency> 2 3 <groupId>javax.sql</groupId> 4 5 <artifactId>jdbc-stdext</artifactId> 6 7 <version>2.0</version> 8 9 <scope>system</scope> 10 11 <systemPath>${java.home}/lib/rt.jar</systemPath> 12 13 </dependency>
6) import(Maven 2.0.9及以上):導入依賴范圍。該依賴范圍不會對三種classpath產生實際的影響。
上述除import以外的各種依賴范圍與三種classpath的關系如下:
依賴范圍(scope) 測試classpath 編譯classpath 運行classpath 例子 compile Y Y Y spring-core provided Y servlet-api test Y junit runtime Y Y JDBC驅動實現 system Y Y 本地的,Maven倉庫之外的類庫文件
4.傳遞性依賴和依賴范圍
Maven的依賴是具有傳遞性的,比如A->B,B->C,那麼A間接的依賴於C,這就是依賴的傳遞性,其中A對於B是第一直接依賴,B對於C是第二直接依賴,C為A的傳遞性依賴。
在平時的開發中,如果我們的項目依賴了spring-core,依賴范圍是compile,spring-core又依賴了commons-logging,依賴范圍也是compile,那麼我們的項目對於commons-logging這一傳遞性依賴的范圍也就是compile。第一直接依賴的范圍和第二直接依賴的范圍決定了傳遞性依賴的范圍。我們通過下面這個表格來說明,其中最左邊一欄是第一直接依賴,最上面那一欄為第二直接依賴。中間交叉的是傳遞性依賴范圍。
Compile
Test
Provided
Runtime
Compile
Compile
Runtime
Test
Test
Test
Provided
Provided
Provided
Provided
Runtime
Runtime
Runtime
例如:第一直接依賴范圍是Test,第二直接依賴范圍是Compile,那麼傳遞性依賴的范圍就是Test,大家可以根據這個表去判斷。
仔細觀察一下表格,我們可以發現這樣的規律:
5.依賴調解
下面我們來思考這樣一個問題,如果A->B->C->X(1.0),A->D-X(2.0),即A間接依賴X,我們可以看到有兩條路徑都依賴X,那麼maven將會選擇哪個版本的X?maven當中有一套自己的規則,我們來說明一下,maven傳遞性依賴的一些規則以及如何排除依賴沖突。
Maven裡面對於傳遞性依賴有以下幾個規則:
1) 最短路徑原則:如果A對於依賴路徑中有兩個相同的jar包,那麼選擇路徑短的那個包,路徑最近者優先,上述會選X(2.0)。
2) 第一聲明優先原則:如果A對於依賴路徑中有兩個相同的jar包,路徑長度也相同,那麼依賴寫在前面的優先。例如:A->B->F(1.0),A->C->F(2.0),會選F(1.0)。
3) 可選依賴不會被傳遞,如A->B,B->C,B->D,A對B直接依賴,B對C和D是可選依賴,那麼在A中不會引入C和D。可選依賴通過optional元素配置,true表示可選。如果要在A項目中使用C或者D則需要顯式地聲明C或者D依賴。
6.排除依賴
傳遞性依賴會給項目隱式的引入很多依賴,這極大的簡化了項目依賴的管理,但是有些時候這種特性也會帶來問題,它可能會把我們不需要的jar包也引入到了工程當中,使項目結構變得更復雜。或者你想替換掉默認的依賴換成自己想要的jar包,這時候就需要用到依賴排除。
例如:
1 <dependency> 2 <groupId>org.springframework</groupId> 3 <artifactId>spring-core</artifactId> 4 <version>3.2.8</version> 5 <exclusions> 6 <exclusion> 7 <groupId>commons-logging</groupId> 8 <artifactId>commons-logging</artifactId> 9 </exclusion> 10 </exclusions> 11 </dependency>
例子中spring-core包依賴了commons-logging包,我們使用exclusions元素聲明排除依賴,exclusions可以包含一個或者多個exclusion子元素,因此可以排除一個或者多個傳遞性依賴。需要注意的是,聲明exclusions的時候只需要groupId和artifactId,而不需要version元素,這是因為只需要groupId和artifactId就能唯一定位依賴圖中的某個依賴。換句話說,Maven解析後的依賴中,不可能出現groupId和artifactId相同,但是version不同的兩個依賴。
7.把依賴歸為一類
在項目開發中往往會引入同一個項目中的多個jar包,比如最常見的spring,如果我們項目中用到很多關於Spring Framework的依賴,它們分別是spring-core-3.2.8.RELEASE, spring-beans-3.2.8.RELEASE,spring-context-3.2.8.RELEASE,它們都是來自同一項目的不同模塊。因此,所有這些依賴的版本都是相同的,而且可以預見,如果將來需要升級Spring Framework,這些依賴的版本會一起升級。因此,我們應該在一個唯一的地方定義版本,並且在dependency聲明引用這一版本,這一在Spring Framework升級的時候只需要修改一處即可。
首先使用properties元素定義Maven屬性,實例中定義了一個<springframework.version>子元素,其值為3.2.8.RELEASE,有了這個屬性定義之後,Maven運行的時候會將pom.xml中所有的${springframework.version}替換成實際的值:3.2.8.RELEASE。也就是可以使用$和{}的方式引用Maven的屬性。然後將所有springframework依賴的版本替換成<version>${springframework.version}</version>這個樣子,就和在Java代碼中定義了一個不變的常量一樣,以後要升級版本就只需要把這個值改了。
給大家一個完整的Maven配置實例,如果有在使用maven+spring+springMVC+Mybatis+Oracle數據庫的朋友可以直接拿去改造成自己項目所需的父pom,配置如下:
1 <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"> 2 <modelVersion>4.0.0</modelVersion> 3 4 <groupId>com.uidp</groupId> 5 <artifactId>UidpParent</artifactId> 6 <version>0.0.1-SNAPSHOT</version> 7 <packaging>pom</packaging> 8 9 <name>UidpParent</name> 10 <url>http://maven.apache.org</url> 11 12 <properties> 13 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 14 15 <repository-url>http://192.168.0.70:8081/content/groups/public/</repository-url> 16 17 <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version> 18 <maven-war-plugin.version>2.4</maven-war-plugin.version> 19 <maven-javadoc-plugin.version>2.9.1</maven-javadoc-plugin.version> 20 <maven-release-plugin.version>2.4.1</maven-release-plugin.version> 21 <maven-deploy-plugin.version>2.7</maven-deploy-plugin.version> 22 23 24 25 <junit.version>4.11</junit.version> 26 <oracle.version>10.2.0.4</oracle.version> 27 <springframework.version>3.2.8.RELEASE</springframework.version> 28 <mybatis.version>3.2.2</mybatis.version> 29 <mybatis-spring.version>1.2.0</mybatis-spring.version> 30 <mysql-driver.version>5.1.25</mysql-driver.version> 31 <aspectjweaver.version>1.7.3</aspectjweaver.version> 32 33 <commons-dbcp.version>1.4</commons-dbcp.version> 34 <commons-pool.version>1.5.5</commons-pool.version> 35 <commons-fileupload.version>1.2.2</commons-fileupload.version> 36 37 <log4j.version>1.2.17</log4j.version> 38 <slf4j-api.version>1.7.5</slf4j-api.version> 39 <slf4j-log4j12.version>1.7.5</slf4j-log4j12.version> 40 41 <freemarker.version>2.3.19</freemarker.version> 42 43 <jackson-core.version>2.5.0</jackson-core.version> 44 <jackson-mapper-asl.version>1.9.7</jackson-mapper-asl.version> 45 46 <javax.servlet-api.version>3.0.1</javax.servlet-api.version> 47 <jsp-api.version>2.2</jsp-api.version> 48 <kryo.version>1.04</kryo.version> 49 <snakeyaml.version>1.8</snakeyaml.version> 50 <jedis.version>2.0.0</jedis.version> 51 <commons-lang.version>2.6</commons-lang.version> 52 53 54 <mockito-core.version>1.8.5</mockito-core.version> 55 <powermock-core.version>1.4.9</powermock-core.version> 56 <powermock-api-mockito.version>1.4.9</powermock-api-mockito.version> 57 <powermock-module-junit4.version>1.4.9</powermock-module-junit4.version> 58 59 60 </properties> 61 62 <dependencyManagement> 63 <dependencies> 64 65 <dependency> 66 <groupId>junit</groupId> 67 <artifactId>junit</artifactId> 68 <version>${junit.version}</version> 69 <scope>test</scope> 70 </dependency> 71 72 <!-- spring jar begin --> 73 <dependency> 74 <groupId>org.springframework</groupId> 75 <artifactId>spring-web</artifactId> 76 <version>${springframework.version}</version> 77 </dependency> 78 79 <dependency> 80 <groupId>org.springframework</groupId> 81 <artifactId>spring-webmvc</artifactId> 82 <version>${springframework.version}</version> 83 </dependency> 84 85 <dependency> 86 <groupId>org.springframework</groupId> 87 <artifactId>spring-beans</artifactId> 88 <version>${springframework.version}</version> 89 </dependency> 90 91 <dependency> 92 <groupId>org.springframework</groupId> 93 <artifactId>spring-context</artifactId> 94 <version>${springframework.version}</version> 95 </dependency> 96 97 <dependency> 98 <groupId>org.springframework</groupId> 99 <artifactId>spring-context-support</artifactId> 100 <version>${springframework.version}</version> 101 </dependency> 102 103 <dependency> 104 <groupId>org.springframework</groupId> 105 <artifactId>spring-core</artifactId> 106 <version>${springframework.version}</version> 107 </dependency> 108 109 <dependency> 110 <groupId>org.springframework</groupId> 111 <artifactId>spring-jdbc</artifactId> 112 <version>${springframework.version}</version> 113 </dependency> 114 115 <dependency> 116 <groupId>org.springframework</groupId> 117 <artifactId>spring-tx</artifactId> 118 <version>${springframework.version}</version> 119 </dependency> 120 121 <dependency> 122 <groupId>org.springframework</groupId> 123 <artifactId>spring-test</artifactId> 124 <version>${springframework.version}</version> 125 </dependency> 126 127 <dependency> 128 <groupId>org.springframework</groupId> 129 <artifactId>spring-expression</artifactId> 130 <version>${springframework.version}</version> 131 </dependency> 132 133 <dependency> 134 <groupId>org.springframework</groupId> 135 <artifactId>spring-aop</artifactId> 136 <version>${springframework.version}</version> 137 </dependency> 138 <!-- spring jar end --> 139 140 <dependency> 141 <groupId>org.mybatis</groupId> 142 <artifactId>mybatis</artifactId> 143 <version>${mybatis.version}</version> 144 </dependency> 145 146 <dependency> 147 <groupId>org.mybatis</groupId> 148 <artifactId>mybatis-spring</artifactId> 149 <version>${mybatis-spring.version}</version> 150 </dependency> 151 152 <dependency> 153 <groupId>mysql</groupId> 154 <artifactId>mysql-connector-java</artifactId> 155 <version>${mysql-driver.version}</version> 156 </dependency> 157 158 <dependency> 159 <groupId>com.oracle</groupId> 160 <artifactId>ojdbc14</artifactId> 161 <version>${oracle.version}</version> 162 </dependency> 163 164 <dependency> 165 <groupId>org.aspectj</groupId> 166 <artifactId>aspectjweaver</artifactId> 167 <version>${aspectjweaver.version}</version> 168 </dependency> 169 170 171 <dependency> 172 <groupId>commons-dbcp</groupId> 173 <artifactId>commons-dbcp</artifactId> 174 <version>${commons-dbcp.version}</version> 175 </dependency> 176 <dependency> 177 <groupId>commons-pool</groupId> 178 <artifactId>commons-pool</artifactId> 179 <version>${commons-pool.version}</version> 180 </dependency> 181 <dependency> 182 <groupId>commons-fileupload</groupId> 183 <artifactId>commons-fileupload</artifactId> 184 <version>${commons-fileupload.version}</version> 185 </dependency> 186 187 188 <!-- log jar --> 189 <dependency> 190 <groupId>log4j</groupId> 191 <artifactId>log4j</artifactId> 192 <version>${log4j.version}</version> 193 </dependency> 194 <dependency> 195 <groupId>org.slf4j</groupId> 196 <artifactId>slf4j-api</artifactId> 197 <version>${slf4j-api.version}</version> 198 </dependency> 199 <dependency> 200 <groupId>org.slf4j</groupId> 201 <artifactId>slf4j-log4j12</artifactId> 202 <version>${slf4j-log4j12.version}</version> 203 </dependency> 204 205 <!-- freemarker --> 206 <dependency> 207 <groupId>org.freemarker</groupId> 208 <artifactId>freemarker</artifactId> 209 <version>${freemarker.version}</version> 210 </dependency> 211 212 213 <!-- jackson --> 214 <dependency> 215 <groupId>com.fasterxml.jackson.core</groupId> 216 <artifactId>jackson-core</artifactId> 217 <version>${jackson-core.version}</version> 218 </dependency> 219 <dependency> 220 <groupId>org.codehaus.jackson</groupId> 221 <artifactId>jackson-mapper-asl</artifactId> 222 <version>${jackson-mapper-asl.version}</version> 223 </dependency> 224 225 <dependency> 226 <groupId>javax.servlet</groupId> 227 <artifactId>javax.servlet-api</artifactId> 228 <version>${javax.servlet-api.version}</version> 229 <scope>provided</scope> 230 </dependency> 231 232 <dependency> 233 <groupId>javax.servlet.jsp</groupId> 234 <artifactId>jsp-api</artifactId> 235 <version>${jsp-api.version}</version> 236 <scope>provided</scope> 237 </dependency> 238 239 <dependency> 240 <groupId>com.googlecode</groupId> 241 <artifactId>kryo</artifactId> 242 <version>${kryo.version}</version> 243 </dependency> 244 245 <dependency> 246 <groupId>org.yaml</groupId> 247 <artifactId>snakeyaml</artifactId> 248 <version>${snakeyaml.version}</version> 249 </dependency> 250 251 <dependency> 252 <groupId>redis.clients</groupId> 253 <artifactId>jedis</artifactId> 254 <version>${jedis.version}</version> 255 </dependency> 256 257 <dependency> 258 <groupId>commons-lang</groupId> 259 <artifactId>commons-lang</artifactId> 260 <version>${commons-lang.version}</version> 261 </dependency> 262 263 264 <dependency> 265 <groupId>org.mockito</groupId> 266 <artifactId>mockito-core</artifactId> 267 <version>${mockito-core.version}</version> 268 <scope>test</scope> 269 </dependency> 270 271 <dependency> 272 <groupId>org.powermock</groupId> 273 <artifactId>powermock-core</artifactId> 274 <version>${powermock-core.version}</version> 275 <scope>test</scope> 276 </dependency> 277 278 <dependency> 279 <groupId>org.powermock</groupId> 280 <artifactId>powermock-api-mockito</artifactId> 281 <version>${powermock-api-mockito.version}</version> 282 <scope>test</scope> 283 </dependency> 284 285 <dependency> 286 <groupId>org.powermock</groupId> 287 <artifactId>powermock-module-junit4</artifactId> 288 <version>${powermock-module-junit4.version}</version> 289 <scope>test</scope> 290 </dependency> 291 292 293 </dependencies> 294 </dependencyManagement> 295 296 <distributionManagement> 297 <repository> 298 <id>releases</id> 299 <name>public</name> 300 <url>http://59.50.95.66:8081/nexus/content/repositories/releases</url> 301 </repository> 302 <snapshotRepository> 303 <id>snapshots</id> 304 <name>Snapshots</name> 305 <url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url> 306 </snapshotRepository> 307 </distributionManagement> 308 309 310 311 <build> 312 <plugins> 313 314 <plugin> 315 <groupId>org.apache.maven.plugins</groupId> 316 <artifactId>maven-compiler-plugin</artifactId> 317 <version>${maven-compiler-plugin.version}</version> 318 <configuration> 319 <source>1.7</source> <!-- 源代碼使用的開發版本 --> 320 <target>1.7</target> <!-- 需要生成的目標class文件的編譯版本 --> 321 </configuration> 322 </plugin> 323 324 <plugin> 325 <groupId>org.apache.maven.plugins</groupId> 326 <artifactId>maven-javadoc-plugin</artifactId> 327 <version>${maven-javadoc-plugin.version}</version> 328 </plugin> 329 330 331 <plugin> 332 <groupId>org.apache.maven.plugins</groupId> 333 <artifactId>maven-release-plugin</artifactId> 334 <version>${maven-release-plugin.version}</version> 335 </plugin> 336 337 <plugin> 338 <groupId>org.apache.maven.plugins</groupId> 339 <artifactId>maven-deploy-plugin</artifactId> 340 <version>${maven-deploy-plugin.version}</version> 341 <configuration> 342 <updateReleaseInfo>true</updateReleaseInfo> 343 </configuration> 344 </plugin> 345 346 347 348 </plugins> 349 </build> 350 351 352 <pluginRepositories> 353 <pluginRepository> 354 <id>nexus</id> 355 <name>nexus</name> 356 <url>${repository-url}</url> 357 <releases> 358 <enabled>true</enabled> 359 </releases> 360 <snapshots> 361 <enabled>true</enabled> 362 </snapshots> 363 </pluginRepository> 364 </pluginRepositories> 365 366 367 </project>
結束語:日月如梭,光陰似箭。不知不覺馬上就要到2017年了,很多時候真的覺得不是我們年輕人不想做的更好,大多數時候是被前面的人給壓迫的越來越油條了,所謂前人如此,卻要求後人如何如何,其實想想也覺得蠻搞笑的。前人盡情的揮灑著智慧,玩著小心思不斷的在壓搾著年輕人,年輕人無奈的在這麼個環境中掙扎求存。本以為離開了一個坑會迎來一個美好的未來,沒想到的是不知不覺又跳入了一個更深的大坑,甚至有些坑還是隱形的,沒有點特異功能還真不一定能夠發現。不過話雖如此,作為新一代的年輕人,一定要經得過驚濤駭浪,何況是這點小風小浪。