第4章--Maven
Maven实战
Java Web应用的部署:
手动式:
编译:javac -cp $CATALINA_HOME/lib/servlet-api.jar web-inf/classes/package/NoodlesServlet.java
打包:jar cvf Restaurant.war .
移动:mv Restaurant.war .../webapps/
项目复杂时:比如项目文件很多 -- IDE如eclipse -->
IDE式:(如eclipse)
下载第三方依赖包,去哪里下载?
目录结构怎么定?
编译、测试、打包、发行,构建流程怎么统一?
项目代码共享和依赖,怎么做?
版本如何管理?
--> 常用工具解决以上问题
Maven:
Java Web的项目构建和依赖管理工具
Apache基金会,开源,由Java写的
选择Maven的理由:
默认对于目录结构进行了限定(约定/惯例优先原则)
提供了三方依赖的管理--解决了依赖的维护问题
提供了一致的项目构建管理方式--减少了构建工作量,降低学习成本
插件式的架构,大量可重用插件
很方便集成了IDE
Maven的安装:
依赖JDK
官网:http://maven.apache.org/
$ brew install maven3
配置环境变量:
M2_HOME=/dir to maven/
PATH=$PATH:$M2_HOME/bin
Maven在构建项目的时候使用的配置:pom.xml
Maven项目的坐标:定位唯一项目(不可重复)
groupId:组织
artifactId:项目标识符
version:版本号(i.e. <version>1.0.0-SNAPSHOT</version>) (SNAPSHOT表示为开发版本)
其他属性:
packaging:类型,i.e. war
dependencies:依赖的项目
基本命令:
mvn archetype:generate:使用模板生成项目
mvn compile:编译
mvn test:单元测试
mvn package:打包War
mvn deploy:部署
mvn site:生成项目相关站点,在线文档之类
mvn clean:清理
mvn install:把包安装到本地仓库,可对其进行依赖
Tomcat插件:Tomcat官方提供的Maven插件:实现在Maven中内嵌启动一个Tomcat
mvn help:describe -Dplugin=tomcat7
常见命令:
mvn tomcat7:run:启动一个嵌入的Tomcat实例
mvn tomcat7:deploy;mvn tomcat7:undeploy等
如何使用Maven管理Tomcat项目:
mkdir 创建目录
mvn archetype:generate -DgroupId=com.netease.restaurant -DartifactId=Restaurant -Dpackage=com.netease -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp 创建项目
生成的目录结构:
生成pom.xml:
缺少对servlet的依赖:在<dependencies></dependencies>中添加依赖
配置插件:编译器的插件和tomcat插件
在main下建立java/com/netease文件夹,并把上节课的Java文件拷贝到该文件夹下
拷贝静态资源到webapp文件夹下
替换WEB-INF下的web.xml为上节课写的web.xml
删除webapp下的index.jsp
运行项目:(注意,在Restaurant目录下运行,否则报错)
mvn tomcat7:run
and it is running
open another terminal tab and curl http://localhost:8080/Restaurant/noodles
it works.
多个项目之间的依赖问题:
Extend Noodle case:
Add a Kitchen for the purpose of handling with vegetable
Noodle is depended on Kitchen‘s vegetable
Solution:
Add a Kitchen project:
mvn archetype:generate -DgroupId=com.netease.restaurant -DartifactId=Kitchen -Dpackage=com.netease -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart
// -DarchetypeArtifactId=maven-archetype-quickstart means its a java program rather than a web app
change App.java to Kitchen.java
package com.netease; public class Kitchen { public static String makeNoodles(String vegetable) { if (vegetable == null) { vegetable = "Tomato"; } StringBuffer s = new StringBuffer(); s.append("<html><body> ") .append("<h1> Noodles with ") .append(vegetable) .append("</h1> ") .append("</body></html>"); return s.toString(); } }
为了管理这两个子项目,在顶上创建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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.netease.restaurant</groupId> <artifactId>restaurant-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <name> Multi modules demo </name> <modules> <module>Restaurant</module> <module>Kitchen</module> </modules> </project>
修改Kitchen子项目和Restaurant子项目的pom.xml文件(添加parent)
修改NoodleServlet.java:
加入对Kitchen的依赖:import com.netease.Kitchen;
修改vegetable部分的代码
由于NoodleServlet.java对Kitchen有了依赖,所以在Restaurant的pom.xml中加入dependency
NB:不要加入<packaging>jar</packaging>
在main目录下创建resources文件夹
修改完成,试一试:
mvn install (在最顶端的pom.xml所在目录下)
install成功,进入Restaurant目录,运行mvn tomcat7:run,成功
抛开bash,使用IDE试一试:
打开eclipse,安装maven插件
Help->Install New Software->...cannot find it:
solution -> https://stackoverflow.com/questions/8620127/maven-in-eclipse-step-by-step-installation
import the project:
import->Maven->Existing Maven Projects
Root Directory: maven-restaurant (with pom.xml)
How to run:
右键Restaurant->Run Configuration->Maven Build
Name: Restaurant
Base directory: ${workspace_loc:/Restaurant}
Goals: tomcat7:run
Run.
curl works.
Maven核心概念
约定(惯例)优先于配置:对于一些配置,给予默认值,就无需用户进行配置
约定有:
标准的目录结构:
*.java位于src/main/java目录下
*.class位于target目录下
配置文件 如web.xml 及静态文件 如SoyMilk.html 位于src/main/webapp目录下
etc.
项目描述符:pom.xml
Project Object Model 项目对象模型
一个pom.xml定义了一个maven项目
一个构建(artifact)等价于一个项目(project)
配置:
项目类型<packaging>:pom, jar, war
坐标:groupId, artifactId, version
属性:${property}
依赖 <dependency>:详见下
构建配置:i.e. maven-compiler插件的配置项
多项目、继承:<parent> <module>
项目总体信息:name, author等
问题:
多个项目配置重复
修改繁琐,比如依赖关系等
依赖版本不一致
配置管理混乱
怎么办?
借助OO思想:pom.xml的继承或覆盖 <parent>
常用继承项:
坐标属性,如groupId;依赖关系的配置;插件配置;一般性信息,如开发者信息等
继承的根在哪?
Super POM:所有的Maven项目的POM都继承Super POM(默认继承于Super POM)
Super POM是Maven的组成部分,定义了一组被所有项目共享的默认设置
如默认的文件位置,统一的插件配置,默认的中央仓库配置等
mvn help:effective-pom:把所有的继承项都继承下来之后的pom内容
i.e. in Restaurant, run mvn help:effective-pom --> tons of contexts are shown.
多模块构建中:
有一个parent项目,类型是pom,在该pom中定义<modeles><module>
子模块中配置<parent>以继承
NB: 统一配置提到parent项目中
依赖配置:
依赖坐标:groupId, artifactId, version
scope:依赖的范围,常见compile(default): 编译的时候用,打包的时候也会打包 / provided:编译时需要,打包时不需要
用于继承的pom配置:<dependencyManagement>
i.e.
<project> <dependencyManagement> <dependencies> <dependency> ...
依赖如何寻找呢?
仓库:
用于统一存储所有maven项目,并提供共享的空间
仓库分类:
本地仓库:在本地目录内,很多时候用于缓存,下次使用无需重新从远程仓库下载。
默认路径 ~/.m2/repository
远程仓库:本地仓库查找优先,若找不到,到远程仓库查找并下载构件至本地仓库
项目在远程仓库中的路径 /<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>
远程仓库分类:
中央仓库:The Central Repository (自带仓库,有大部分项目,但在中国访问速度较慢)
其他公共仓库:如开源中国社区的maven镜像(oschina.net)
私服:比如公司内部(artifactory),相当于做一个代理
远程仓库的配置:
配置文件settings.xml(对所有依赖而言)
在pom.xml为依赖指定repositories(对单个依赖而言)
maven的架构:
插件(Plugin)式架构:很小的一个引擎+很多插件
所有的插件本身也是一个maven构件,由maven仓库管理
每一个插件提供多个目标(Goal)。调用目标的格式:mvn <Plugin>:<Goal>
maven的构建生命周期:
一组有序的阶段:编译,打包,部署等
会根据项目类型来确定每个阶段的动作
三套独立的生命周期:
一些命令:mvn clean/ mvn clean install /mvn package/
clean (删除项目的构建):pre-clean (预处理工作) --> clean (移出构建过程中生成的文件) --> post-clean (善后)
site (生成站点文档):pre-site --> site --> post-site -->site-deploy
default (详解):... -> process-resources -> compile -> ... -> test -> package -> install -> deploy
默认生命周期:整个项目构建的模型
validate:验证项目是否正确,是否拥有构建所需的完整信息
process-resources:复制资源文件到目录下,方便之后打包
compile:编译源代码
test:单元测试
package:打包编译好的代码,比如jar包、war包等
install:把调用的包安装到本地仓库
deploy:最后一个阶段,将包上传到远程仓库
maven的生命周期阶段是与目标绑定的,用户通过制定生命周期阶段会隐式地通过插件执行任务
i.e. mvn compile --> mvn compiler:compile
生命周期阶段 | 目标 |
process-resources | resources:resources |
compile | compiler:compile |
test | surefire:test |
install | install:install |
deploy | deploy:deploy |
对于package阶段,会根据项目类型不同,绑定到不同的目标
插件的配置:<plugins><plugin>......</plugin>...
查看configuration配置:mvn help:describe -Dplugin=<plugin_name> -Dgoal=<goal> -Ddetail
对于父pom的继承:pluginManagement
maven的内建插件:
i.e. help:mvn help:help -Ddetail=true
tomcat7将tomcat嵌入到maven的plugin中、exec简单的把一个jar包跑起来
maven的全局配置文件${M2_HOME}/conf/settings.xml
本地仓库、远程仓库等
pom文件summary:
项目关系配置:坐标、多项目、继承关系、依赖
属性:${property}
构建配置:插件配置、生命周期绑定
普通项目属性:作者信息、使用的开源协议
maven项目构建summary:
pom.xml:描述项目构建 -- 项目对象模型
依赖仓库:存放三方依赖 -- 依赖管理(从pom.xml读取配置信息)
构建生命周期,不同的构建阶段,depends on particular plugin
构建产出资源文件、源文件、中间产出文件、class文件、打包文件等
课程summary:
默认标准的目录结构
pom继承、Super POM、多项目管理
依赖及依赖配置、依赖配置的继承
仓库
构建生命周期
插件plugin、目标goal
Maven单元测验:http://www.itnose.net/detail/6632794.html
Maven单元作业:https://my.oschina.net/hava/blog/738572
http://www.cnblogs.com/windJcoder/p/5382143.html