不积跬步,无以至千里

Maven实战


这篇文章记录下工作中需要的maven相关的知识

maven是目前普遍使用的项目管理和构建工具,maven的使用不仅仅包括基本的命令,还涉及到和项目的集成.

怎么在项目中使用maven

在pom文件中添加对jar包的依赖,使得打开项目时,自动下载依赖的jar包

在pom文件中添加maven相关的插件,使得在项目启动时,自动做代码检查,打包等

常用的maven命令

在target下生成项目的jar包或war包:mvn package -Pdev(指定使用dev环境)

把jar包复制到本地仓库:mvn install

本地打包并上传到远程仓库:mvn deploy

在打包时,跳过测试:mvn -Dmaven.test.skip=true install/deploy

mvn的命令存在依赖关系,如在执行deploy命令时,需要先生成jar包并复制到本地仓库.但各个命令执行时又不会强依赖.因为maven会自动执行前置命令,比如在执行deploy命令时,会首先做build,然后install,最后deploy

检查依赖冲突:mvn enforcer:enforce

maven的pom文件设定jar包依赖的代码规范

在pom.xml文件中,包括如下元素:

<?xml version="1.0" encoding="UTF-8"?>
<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>
    <parent>
        <groupId>**</groupId>
        <artifactId>**</artifactId>
        <version>*.*.*</version>
    </parent>
    <groupId>**</groupId>
    <artifactId>**</artifactId>
    <packaging>pom</packaging>
    <version>*.*.*</version>
    <name>**</name>
    <modules>
        <module>**</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    
        <*.version>3.0.4</*.version>    
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>**</groupId>
                <artifactId>**</artifactId>
                <version>*.*.*</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>            
        </dependencies>
    </dependencyManagement>
</project>

以上为一个标准的父pom,其中主要定义依赖的jar包的版本

<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>
    <parent>
        <groupId>**</groupId>
        <artifactId>**</artifactId>
        <version>*.*.*</version>
    </parent>
    <groupId>**</groupId>
    <artifactId>**</artifactId>
    <packaging>war</packaging>
    <name>service Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <profiles.dir>src/profiles</profiles.dir>
    </properties>
    <dependencies>
        <dependency>
            <groupId>**</groupId>
            <artifactId>**</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>**</groupId>
            <artifactId>**</artifactId>
        </dependency>        
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources.${deploy.type}</directory>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.8</version>
                <configuration>
                    <projectNameTemplate>[artifactId]</projectNameTemplate>
                    <wtpmanifest>true</wtpmanifest>
                    <wtpapplicationxml>true</wtpapplicationxml>
                    <wtpversion>2.0</wtpversion>
                    <manifest>${basedir}/src/main/resources/META-INF/MANIFEST.MF</manifest>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <failOnError>true</failOnError>
                    <verbose>true</verbose>
                    <fork>true</fork>
                    <compilerArgument>-nowarn</compilerArgument>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>           
        </plugins>
        <finalName>service</finalName>
    </build>
    <profiles>
        <profile>
            <id>dev</id>
            <build>
                <resources>
                    <resource>
                        <directory>${profiles.dir}/dev</directory>
                    </resource>
                </resources>
            </build>
        </profile>
    </profiles>
</project>

以上为一个子pom,除了引入依赖的jar包之外,还标示这个模块打war包,同时定义了profile和plugin的相关配置.需要注意的是,为了对依赖的jar包的版本做统一的管理,最好要求在父pom的dependencyManagement标签下集中定义依赖版本.

说明下标签含义

profile:定义各种开发环境的变量,在以上文件中,指定了不同环境依赖资源文件的路径

dependencyManagement:管理依赖包,但不会引入项目的jar包.

scope:指定jar包依赖的传递性,并影响构建路径.默认为compile

其中scope有以下几种

compile:项目中的所有环境中均可用,并且依赖这个项目的项目也可以用到,如果要更换依赖包,还需要直接修改源代码

provided:只用于编译和测试,运行阶段由jdk或运行容器来提供依赖,如servlet-api.jar,仅仅是引入api,但是要求每个容器有不同的实现,这样就可以在不同的容器运行

runtime:运行和test可用,编译路径不可用,比如日志slf4j的实现logback、jdbc的实现 mysql, 此时是不能import它的类的,这样就可以在运行时很方便的更换实现类,这是针对于接口编程

test:只用于测试的编译和执行,不具有传递性,也就是依赖该jar包的项目无法引入这个jar包,用于编译和运行测试代码 ,不会随项目发布

system:

import:只有在dependencyManagement标签内才可以使用,表示使用一系列依赖来替换这个引入的依赖,不具有传递性

依赖冲突

在引入jar包时,可能会存在多个jar包同时依赖一个jar包,且这个jar包依赖的版本不同的情况,这样就会造成依赖冲突.此时,maven怎么确定使用那个版本呢?

有两个原则,一个是最短路径依赖原则,另一个是就近原则,也就是哪个先定义就先用哪个.

依赖冲突可能会造成程序执行的不确定,要避免出现依赖冲突的情况.

当检查出现依赖冲突时,可以通过两个方式来解决,一种是排除法,但是这种方式有可能会造成NoClassDefException异常;比较安全的做法是利用maven最短路径原则,在dependencyManagement中重新执行版本.

在项目中使用netty启动web服务的方法

首先在pom文件中添加maven的netty插件:

    <build>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>${jetty.version}</version>
                <configuration>
                    <contextPath>/</contextPath>
                    <connectors>
                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                            <port>8080</port>
                        </connector>
                    </connectors>
                </configuration>
            </plugin>
        </plugins>
    </build>

然后在IDE中配置使用maven启动项目,在命令行配置中添加:netty:run即可