Maven原理与实践
Maven原理与实践
一.maven简介
- 何为maven
Maven是一个采用纯Java编写的开源项目管理工具。Maven采用了一种被称之为project object model (POM)概念来管理项目,所有的项目配置信息都被定义在一个叫做POM.xml的文件中,通过该文件,Maven可以管理项目的整个声明周期,包括编译,构建,测试,发布,报告等等。目前Apache下绝大多数项目都已经采用Maven进行管理。而Maven本身还支持多种插件,可以方便更灵活的控制项目。
Maven是面向技术层面,针对Java开发项目管理工具,它提供了构建工具所提供功能的超集,除了构建功能之外,Maven还可以管理项目结构、管理依赖关系、生成报告、生成Web站点、有助于团队成员之间的交流与协作。
1.2maven的优势
- 指导开发:提供了Java项目的最佳开发实践,自由开发项目骨架而可自动生成项目结构。
- 自动编译:不仅仅只像Ant自动编译,还包括测试,打包,发布,文档生成,项目站点生成……
- 依赖管理:Maven可以方便地管理应用程序依赖,例如第三方依赖、模型依赖
- 无限扩展:插件模式可以无限增强Maven功能,例如通过Tomcat、Jetty插件可以自由控制其服务器。
- 持续集成:鼓励开发者积极提交代码,更早地发现程序错误,在并行开发中稳妥推进。
- 开发协作:更简单和谐的团队协作
1.3maven名词解释
- Project:任何您想build的事物,Maven都可以认为它们是工程。这些工程被定义为工程对象模型(POM,Poject Object Model)。一个工程可以依赖其它的工程;一个工程也可以由多个子工程构成。
- POM:POM(pom.xml)是Maven的核心文件,它是指示Maven如何工作的元数据文件,类似于Ant中的build.xml文件。POM文件位于每个工程的根目录中。
- GroupId:groupId是一个工程的在全局中唯一的标识符,一般地,它就是工程名。groupId有利于使用一个完全的包名,将一个工程从其它有类似名称的工程里区别出来。
- Artifact:artifact 是工程将要产生或需要使用的文件,它可以是jar文件,源文件,二进制文件,war文件,甚至是pom文件。每个artifact都由groupId和 artifactId组合的标识符唯一识别。需要被使用(依赖)的artifact都要放在仓库(见Repository)中,否则Maven无法找到 (识别)它们。
- Dependency:为了能够build或运行,一个典型的Java工程会依赖其它的包。在Maven中,这些被依赖的包就被称为dependency。dependency一般是其它工程的artifact。
- Plug-in:Maven是由插件组织的,它的每一个功能都是由插件提供的。插件提供goal(类似于Ant中的target),并根据在POM中找到的元数据去完成工作。主要的Maven插件要是由Java写成的,但它也支持用Beanshell或Ant脚本写成的插件。
- Repository:仓库。
二.maven原理简介
Maven的主要组件如下图所示:
项目对象模型(Project Object Model,POM)描述项目的各个方面。尽管对于 POM 的物理表示没有内在的限制,但 Maven 开发人员通常使用一个 XML 项目文件(project.xml)。该 XML 文件格式由位于 Maven 安装目录中的 XML 模式(maven-project.xsd)定义。
通常,pom.xml 文件由三个主要部分组成:
- 项目管理部分包括项目的组织、开发人员名单、源代码位置和错误跟踪系统 URL 等信息。
- 项目相关性部分包括关于项目相关性的信息。当前 Maven 实现(1.0 beta 测试版 8)仅支持 JAR 文件相关性。
- 项目构建和报告部分包含项目构建信息(如源代码目录、单元测试用例目录)和要在构建中生成的报告。
清单 1. 主 project.xml 框架
2.1.1项目管理部分
项目管理部分(如清单 2 所示)主要包括可选项。在此部分中指定开发人员名单(带有正确的标识),当您希望获得更改日志(Change Log)报告和开发活动(Development Activity)报告时尤其要这么做。
- 一个Java构件的五大坐标元素:
- groupId:组ID
- artifactId:实际项目的ID
- version:版本
- package:包类型,如JAR、EAR、POM…
- classifier:分类,如二进制包,源、文档
通过这种规则就可以定位到世界上任何一个构件
1.2.1.2项目相关性部分
我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可。
groupId | 告诉 Maven 资源库内哪个子目录中包含相关性文件。 |
artifactId | 告诉 Maven 该构件的唯一标识。 |
version | 表示相关性的版本号。 |
jar | (可选的)表示相关性的 JAR 文件。在绝大多数情况下,可以从相关性的 <artifactId> 和 <version> 构造 JAR 文件的名称。 |
type | (可选的)相关性的类型;如 jar 和分发版等。缺省值是 jar。 |
url scope | (可选的)相关性项目的 URL,在相关性是在因特网上找到的第三方库时有用。 (可选的)依赖的范围,下面会进行详解 |
exclusions | (可选的)用来排除传递性依赖,下面会进行详解 |
1.依赖范围
Maven有以下几种依赖范围:
compile: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。
test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子就是JUnit,它只有在编译测试代码及运行测试的时候才需要。
provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。
runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主 代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
system: 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过 systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此 应该谨慎使用。systemPath元素可以引用环境变量。
2. 传递性依赖
我们可以看到此项目引入依赖junit和spring-core,我们可以在Maven仓库中查找spring-core构件,如图:
点击POM我们会看到该文件包含了一个commons-logging依赖:
那么该依赖会传递到当前项目中,这就是依赖的传递性,打开项目查看Maven dependencies:
3. 可选依赖
有时候我们不想让依赖传递,那么可配置该依赖为可选依赖,将元素optional设置为true即可,例如:
那么依赖该项目的另一项目将不会得到此依赖的传递
4.依赖调解
第一原则:路径最短者优先,A -> B -> C ->X(1.0), A -> D -> X(2.0),此时A只会依赖X(2.0)
第二原则:第一声明者优先,当第一原则无法解决依赖冲突时,则按在pom中依赖声明的顺序决定
5. 排除依赖
当我们引入第三方jar包的时候,难免会引入传递性依赖,有些时候这是好事,然而有些时候我们不需要其中的一些传递性依赖
比如上例中的项目,我们不想引入传递性依赖commons-logging,我们可以使用exclusions元素声明排除依 赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖。需要注意的是,声明exclusions 的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖 图中的某个依赖。换句话说,Maven解析后的依赖中,不可能出现groupId和artifactId相同,但是version不同的两个依赖。
如下是一个排除依赖的例子:
6. 依赖归类
如果我们项目中用到很多关于Spring Framework的依赖,它们分别是org.springframework:spring-core:2.5.6, org.springframework:spring-beans:2.5.6,org.springframework:spring- context:2.5.6,它们都是来自同一项目的不同模块。因此,所有这些依赖的版本都是相同的,而且可以预见,如果将来需要升级Spring Framework,这些依赖的版本会一起升级。因此,我们应该在一个唯一的地方定义版本,并且在dependency声明引用这一版本,这一在 Spring Framework升级的时候只需要修改一处即可。
1.2.1.3项目构建部分
项目构建和报告部分(如清单 4 所示)包含用于配置某些 Maven 插件的重要构建和报告信息。例如,可以配置 Maven 在站点文档生成时包含还是排除某些报告。
1.编译源代码: mvn compile
2. 编译测试代码:mvn test-compile
3. 运行测试:mvn test
4. 产生site:mvn site
5. 打包:mvn package
6. 在本地Repository中安装jar:mvn install
7. 清除产生的项目:mvn clean
8. 生成eclipse项目:mvn eclipse:eclipse
9. 生成idea项目:mvn idea:idea
10. 组合使用goal命令,如只打包不测试:mvn -Dtest package
11. 编译测试的内容:mvn test-compile
12. 只打jar包: mvn jar:jar
13. 只测试而不编译,也不测试编译:mvn test -skipping compile -skipping test-compile
( -skipping 的灵活运用,当然也可以用于其他组合命令)
14. 清除eclipse的一些系统设置:mvn eclipse:clean
三.资源库
在以前使用Ant的时候,我们会建立一个lib目录在存放我们的jar包,比如项目所依赖的第三方包,每建立一个项目都要建立一个lib,不停的做copy工作,不仅是对于磁盘的浪费,而且也造成了版本管理上的麻烦。而且我们还需要通过提交到svn上来对lib进行管理,但是svn对于这种二进制文件的管理并不出色。
Maven仓库的初衷就是为了解决这个问题,是所有常用的第三方包的集中营。这样所有的Maven项目就可以从这个仓库中获取所需要的资源,Maven仓库中对jar通过Group Id, Atifact Id, version 来管理,所以Maven项目可以很方便的进行依赖管理。你不需要自己来管理这个庞大的资源仓库,当然你可以创建一个公司层面的仓库管理器,这个我在这个章节的后面会介绍。
Maven 仓库的两个概念:本地仓库和远程仓库
本地仓库是远程仓库的一个缓冲和子集,当你构建Maven项目的时候,首先会从本地仓库查找资源,如果没有,那么Maven会从远程仓库下载到你本地仓库。这样在你下次使用的时候就不需要从远程下载了。如果你所需要的jar包版本在本地仓库没有,而且也不存在于远程仓库,Maven在构建的时候会报错,这种情况可能发生在有些jar包的新版本没有在Maven仓库中及时更新。
Maven缺省的本地仓库地址为${user.home}/.m2/repository 。也就是说,一个用户会对应的拥有一个本地仓库。当然你可以通过修改${user.home}/.m2/settings.xml 配置这个地址:
如果你想让所有的用户使用统一的配置那么你可以修改Maven主目录下的setting.xml:
${M2_HOME}/conf/setting.xml
Settings.xml配置介绍
localRepository: 自定义本地库路径,默认在$user.home/.m2中
interactiveMode:
offline:是否每次编译都去查找远程中心库
pluginGroups:插件组,例如org.mortbay.jetty
proxies:通过代理访问外部库
servers:集成认证服务,例如集成Tomcat
mirrors:镜像库,可以指定内部中心库
profiles:个性配置,需要在Activation标签中激活
activeProfiles:表示激活的profile
在 POM 中配置远程仓库
下面我介绍下如何在pom.xml里面配置远程仓库,我们需要在什么时候配置远程仓库呢?当你连接中央仓库的速度比较慢时,或者你为你的公司搭建了 自己的仓库,比如Nexus仓库管理(后面我会介绍),又或者你苏需要的jar存在另外一个公共仓库,比如我们配置一个国内的镜像地址:
配置镜像
如果你想覆盖中央仓库的默认地址,那么这里我们就会使用的镜像了,还在settings.xml里面配置:
内部中心仓库也称私有共享仓库(私服)。一般是由公司自己设立的,只为本公司内部共享使用。它既可以作为公司内部构件协作和存档,也可作为公用类库镜像缓存,减少在外部访问和下载的频率。
Nexus和Artifactory均可搭建仓库服务器。但后者支持LDAP认证,这样就可以将私有仓库的认证集成到公司已经有的LDAP认证服务器。
内部中心库又可以连接第三方库,例如Jboss中心库、Spring中心库,以随时获得最新版本的第三方构件。
四.Eclipse+tomcat+maven+Spring mvc实践
4.1基础环境(eclipse+tomcat+jdk+maven)
1.安装jdk:
下载并安装jdk,(过程比较简单就略过了)。
配置环境变量:按照java 默认安装路径需要配置为:
JAVA_HOME: C:\Program Files\Java\jdk1.6.0_07 (注意JAVA_HOME 路径后面不能有分号。)
path:%JAVA_HOME%\bin;
classpath: %JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
在控制台下输入javac 有结果就表示安装成功了。
2.安装eclipse:
此次采用的是eclipse 4.2,代号Juno。(免安装版,其他版本慎用,测试过helios版本的,照着这个文档配置会有错误)。
只要解压到指定目录即可。
3.安装tomcat:
先安装插件:下载地址:http://www.eclipsetotale.com/tomcatPlugin.html#A3。我用的是tomcatPluginV33.zip。直接把插件解压放到eclipse 安装目录-plugins 目录下。
再把tomcat 文件放到c 盘根目录(自选)。
4.关联
eclipse 关联jdk、tomcat:
在preferences-java- installed jres 中add- 在jre home 中选择jdk 安装目录。(特别注意:不是jre 文件,是jdk. 如果原来是jre 要换成jdk,如下图)
在eclipse 的preferences-server-runtime environmen 中,add-选择与之相关版本的tomcat(这里选择7.0),browse-选择tomcat 根目录,jre 选择安装过的jre。
再在tomcat 选项选择你安装的tomcat 版本,选择tomcat 根目录,ok。浏览器中输入:http://localhost:8080/。就可以检查是否成功安装了tomcat。
5.安装maven:
先安装插件:在eclipse 的marcketplace 输入maven查找,选择maven integration for eclipse,按照向导安装,重启eclipse。在你的新建项目以及prefrences 就有maven这一项了。
再把maven 文件解压到c 盘根目录(自选)。(maven 文件请自行到网站下载,链接:http://www.apache.org/dyn/closer.cgi/maven/maven-3/3.0.4/binaries/apachemaven-3.0.4-bin.zip)
最后关联操作:在preferences 的maven - user settings 中选择maven文件目录目录—conf 文件-- settings.xml。ok.
4.2:使用并配置环境
1.新建maven项目:
File-new-other-maven-maven project---直接下一步--在filte 中输入webapp(这里代表建立web 项目):选择第二个,如图:
下一步后。如下图:
Group ID 一般写大项目名称。Artifact ID 是子项目名称。(我这里分别写IFLYTEK,sms),点击finish。Maven 的web 项目就建好了。
创建好的maven 项目:
2.构建Maven常规目录结构。
在Maven 管理的项目中,文件目录一般都很固定,我们下面就建立一般的web maven 项
目目录结构。构建并运行一个hello 的示例demo。
(1)建立source folder 文件夹:
到Workspace-项目名-src-main 下新建一个文件夹:java。同样的在上级目录src 目录中新建test 文件夹,在test 下新建文件夹:java。在eclipse 右击刷新,目录就出来了。(如果直接新建source folder 会出现问题)。
(2)新建spring 配置文件:(mvc-dispatcher-servlet.xml)
在项目树中找到src-main-webapp-WEB-INF,在这个目录中新建一个文件夹命名为:
pages,用于以后存放jsp 文件(这样会让项目看起来更清晰一点)。同时在WEB-INF 目
录中新建文件,命名为:mvc-dispatcher-servlet.xml
编辑mvc-dispatcher-servlet.xml文件:
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:context ="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.sms"/>
<mvc:annotation-driven/>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
其中<context:component-scan base-package="com"/>代表编译时读取的包(在classpath下新建的包,在文档下几页中我是新建com.sms.controller所以写这个,扫描com目录下的所有文件),<mvc:annotation-driven />代表注释驱动,<value>/WEB-INF/pages/</value>代表前端控制器寻找jsp 的路径。
(3)编辑web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/webapp_
2_4.xsd" id="WebApp_ID" version="2.4">
<display-name>Spring Web MVC Application</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</ context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</ listener>
</web-app>
其中重要的配置是<context-param>中的<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>,它指明了spring 配置文件的目录。(当然也可以用classpath:xxx的方式进行配置, 多个配置文件也可以用“,”隔开)
<servlet-mapping>中的<url-pattern>/</url-pattern>,它代表前端拦截器将拦截所有文件。
这里要特别注意的是<servlet-name>:mvc-dispatcher,因为要对应<param-value>的/WEB-INF/mvc-dispatcher-servlet.xml。比如,如果<servlet-name>为mydispatcher,那么对应的<param-value>必须为mydispatcher- servlet.xml。
(4)配置pom.xml:
<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/mavenv4_
0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>IFLYTEK</groupId>
<artifactId>sms</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>sms Maven Webapp</name>
<url>http://maven.apache.org</ url>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>sms</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
</plugin>
</plugins>
</build>
</project>
maven 通过pom.xml 管理项目依赖的jar 包,通过groupID、artifactId 以及版本号可以唯一确定一个jar 包。这样可以防止老式Web 项目中WEB-INF/lib 下jar 包不一致的问题。
并且maven 还会自动下载添加进的jar 包所依赖的jar 包。
Run as—maven install,就会去自动下载包了。
至此,项目文件结构如图:
(5)Controller 类:
在src/main/java 下新建包:com.sms.controller,在这个包中新建controller
类:HelloController。编辑如下
packagecom.sms.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public classHelloController {
@RequestMapping("/hello.do")
public String index_jsp(ModelMap model){
System.out.println("hello");
model.addAttribute("yan", "yan你好");
return "hello";
}
}
(6)在pages 目录下新建文件hello.jsp,编辑如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+ "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'Login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel=" stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
${yan}</br>
</body>
</html>
下载完毕后,启动tomcat(在build 之前都要先启动tomcat,不然会报build failed 错误)。在run as- maven build—双击新建一个maven build—在Goals 中输入package tomcat:redeploy(关键)(如下图):
点击刚才配置好的,点击菜单栏上的绿色大按钮run,再稍等片刻,等待包的下载。
更多推荐
所有评论(0)