2015年12月30日星期三

Nexus_005:Nexus 2 权限管理

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. Nexus预定义了三个用户:admin、deployment、anonymous。
(1)admin:该用户拥有对Nexus的完全控制,默认密码为admin123。
(2)deployment:该用户能够访问Nexus,浏览仓库内容,搜索,并上传部署构件,但是无法对Nexus进行任何配置,默认密码为deployment123。
(3)anonymous:该用户对应所有未登录的匿名用户,它们可以浏览仓库并进行搜索。
一个用户可以有一个或多个角色,一个角色可以有一个或多个权限,角色还可以包括角色。


   权限列表:




参考文献:
1. 《Maven 实战》 徐晓斌著  

Nexus_004:手工上传第三方库的构件到 Nexus 2 私服

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. 选择一个宿主仓库,比如 3rd party ,接着选择 Artifact Upload 
如果该构件是基于Maven的,那么可以选择From POM,否则就选择GAV Parameters。
接着,用户需要手工输入Maven的坐标。

用户可以上传一个主构件和多个附属构件(即Classfier),最后选择页面最下方的Upload Artifact(s)按钮上传到仓库中。




 访问3rd party仓库的url:http://localhost:8081/nexus/content/repositories/thirdparty/,或者直接到目录 sonatype-work/nexus/storage/thirdparty 下都可以看到刚上传的构件。

参考文献:
1. 《Maven 实战》 徐晓斌著 

Nexus_003:配置 Nexus 2 私服

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. 配置Maven从Nexus下载构件

修改~/.m2/settings.xml,增加profiles部分,定义构件仓库和插件仓库均指向私服,并激活。

<settings>

......
   <profiles>

        <!— Configure the Nexus repository —>

        <profile>
            <id>nexus</id>
            <repositories>
                <repository>
                    <id>nexus</id>
                    <name>Nexus</name>
                    <layout>default</layout>
                    <url>http://localhost:8081/nexus/content/groups/public/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>

            <pluginRepositories>
                <pluginRepository>
                    <id>nexus</id>
                    <name>Nexus</name>
                    <layout>default</layout>
                    <url>http://localhost:8081/nexus/content/groups/public/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </pluginRepository>
            </pluginRepositories>

    </profile>

    <activeProfiles>
        <activeProfile>nexus</activeProfile>
    </activeProfiles>
......
</settings>

2. 配置镜像

为了所有的请求都首先通过私服,修改~/.m2/settings.xml,增加mirrors镜像部分。
<settings>
  ...... 

  <mirrors>
        <mirror>
            <id>nexus</id>
            <mirrorOf>*</mirrorOf>
            <url>http://localhost:8081/nexus/content/groups/public/</url>
        </mirror>
  </mirrors>

  <profile>
            <id>nexus</id>
            <repositories>
                <repository>
                    <id>central</id>
                    <url>http://central/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>

            <pluginRepositories>
                <pluginRepository>
                    <id>central</id>
                    <url>http://central/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </pluginRepository>
            </pluginRepositories>

    </profile>
    ......
</settings>

(1)这样配置镜像后,所有的请求都会首先从私服走。
(2)这里重写中央仓库的目的是允许快照版构件的下载,覆盖了超级POM中中央仓库的配置。
其中的url配置无关紧要,因为已经通过私服与连接中央仓库了。
(3)当Maven需要下载构件时,首先检查central,看该类型的构件是否支持,如果支持,再根据镜像匹配原则转而问私服。

3. 配置 Nexus 认证

如果只为代理外部公共仓库,Nexus的代理仓库就已经满足需要了。
组织内部的构件和无法从公共仓库获取的第三方的构件,需要部署在 Nexus上的宿主仓库中。
为了安全起见,需要在~/.m2/settings.xml中设置认证信息。

<servers>

        <server>
            <id>nexus-releases</id>
            <username>admin</username>
            <password>welcome1</password>
        </server>

        <server>
            <id>nexus-snapshots</id>
            <username>admin</username>
            <password>welcome1</password>
        </server>

</servers>

参考文献:
1. 《Maven 实战》 徐晓斌著

2015年12月28日星期一

Nexus_002:使用 Nexus 2 搜索构件

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. 使用sonatype nexus 提供公有的搜索服务:http://repository.sonatype.org/
 Nexus 提供了关键字搜索、类名搜索、坐标搜索、校验和搜索功能。


搜索后,会清晰的列出构件的坐标及所属仓库。
用户可以直接下载构件,还可以复制根据坐标自动生成的XML依赖声明。

2. 搭建好 nexus 私服后,可以搜索私服上的构件



参考文献:
1. 《Maven 实战》 徐晓斌著  

Nexus_001:使用 Nexus 2 搭建私服

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9


1. 下载并安装 Nexus
下载地址:http://www.sonatype.org/nexus/。
Nexus 分为社区版和专业版,这里使用社区版。
下载最新的Bundle发布版本:nexus-2.12.0-01-bundle.zip。Bundle版本自带了Jetty容器,不需要额外的Web容器就能直接启动Nexus。
unzip nexus-2.12.0-01-bundle.zip 解压后,有两个目录:
(1)nexus-2.12.0-01:包含了启动Nexus所需要的文件,如启动脚本,依赖jar包等等。该目录是必须要有的。
(2)sonatype-work:该目录包含了Nexus生成的配置文件、日志文件、仓库文件。该目录不是必须的,Nexus会在运行时动态创建该目录,其内容对于各个Nexus实例是不同的。不同的用户在不同的机器上使用Nexus有不同的配置和仓库。

ln -s nexus-2.12.0-01 nexus

2. 启动与停止 Nexus
cd nexus/bin
(1)前台启动 Nexus:./nexus console
(2)停止后台 Nexus:./nexus stop
(3)后台启动 Nexus:./nexus start
(4)查看 Nexus 状态:./nexus status
(5)后台重启 Nexus:./nexus restart

访问:http://localhost:8081/nexus/,管理员账户默认:admin/admin123。
如果想要修改Nexus默认的8081端口,修改nexus/conf/nexus.properties即可。

 
点击左边导航栏中的Repositories链接,可以看到所有类型的Nexus仓库。
仓库有四种类型:group、hosted、proxy、virtual。每个仓库的Format为maven2或maven1,Policy为Release或Snapshot。


Nexus 内置的仓库列表:
(1)Central:代理 Maven 中央仓库。
(2)Releases:策略为 Release 的宿主仓库,用来部署组织内部发布版本的构件。
(3)Snapshots:策略为 Snapshots 的宿主仓库,用来部署组织内部快照版本的构件。
(4)3rd Party:策略为 Release 的宿主仓库,用来部署无法从公共仓库获得的第三方发布版本构件。
(5)Apache Snapshots:代理 Apache Maven 仓库的快照版本构件。
(6)Public Repositories:该仓库将所有上述策略为 Release 的仓库聚合并通过一致的地址来提供服务。


Maven 可以直接从宿主仓库下载;也可以从代理仓库下载,代理仓库会间接地从远程仓库下载并缓存构件;为了方便,也可以从仓库组下载构件,仓库组没有实际内容,它会转向宿主仓库或者代理仓库获取实际的构件。

3.  创建并设置宿主仓库
点击Add...按钮,选择 Hosted Repository,配置信息如下:

 

(1)仓库的ID。
(2)仓库的名称。
(3)仓库的类型。
(4)仓库的格式。
(5)仓库的策略。
(6)仓库的默认存储目录。
(7)仓库的自定义存储目录。
(8)仓库的部署策略:只读(禁止部署)、关闭重新部署(同一构件只能部署一次)、允许重新部署。
(9)是否允许浏览仓库。
(10)是否对该仓库进行索引并提供搜索。
(11)是否允许通过URL访问仓库。
(12)当构件没找到时,缓存这一不存在的信息的时间。默认1440分钟,如果构件没找到,在1440分钟之内再查找时,直接返回不存在,而不会再查找文件系统。

4.  创建并设置代理仓库
点击Add...按钮,选择 Proxy Repository,配置信息如下:


(1)远程仓库的地址ID。
(2)是否下载远程仓库的索引,下载索引后,即使没有那些远程构件,用户也可以在本地搜索浏览那些构件信息。
(3)
(4)
(5)校验出错时的策略。
(6)构件缓存的最长时间。对于发布版本默认为-1,表示自第一次下载后一直有效,不再重新下载;对于快照版本默认为1440,表示每隔一天重新缓存代理构件。

5.  创建并设置仓库
点击Add...按钮,选择 Repository Group,配置信息如下:


(1)仓库组没有Releases 和 Snapshots 的区别。
(2)仓库组中所包含的仓库的顺序决定了仓库组遍历其所含仓库的次序,因此要将常用的仓库放在前面。

参考文献:
1. 《Maven 实战》 徐晓斌著 

2015年12月27日星期日

Maven_004:聚合与继承

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. 聚合
实际情况中,一个项目是由多个Maven项目组成的,如果每次构建整个项目都要逐一手工构建Maven项目,那就太麻烦了。
聚合就是解决此类问题的:只需运行一次Maven命令,就可以构建整个项目。

在子Maven项目的上一级目录创建一个父目录,比如account-aggregator,作为聚合项目。
该项目只有一个pom.xml,没有其它内容,因为它的作用就是聚合。
各个子Maven项目依然可以独立构建。

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
    <modules>
        <module>account-email</module>
        <module>account-persist</module>
    </modules>
</project>

(1)modules 中指定包含的子Maven项目,这里的值是子Maven项目的目录名称。
(2)packaging 必须设置为 pom。
(3)modules 中指定子Maven项目。

完成后的项目目录结构如下:
account-aggregator
    -- account-email
        -- pom.xml
        ...
    -- account-persist
        -- pom.xml
        ... 
    -- pom.xml

2. 继承
聚合解决了使用一条Maven命令构建多个Maven项目的问题。
但实际情况中,多个Maven子项目具有共同的属性,建议把这些相同的属性抽取出来,放到一个父 Maven 项目中声明,然后在各个子Maven项目中继承来自父 Maven 项目中声明。

在子Maven项目的同级目录创建一个目录,比如account-parent,作为父项目。
该项目只有一个pom.xml,没有其它内容,因为它的作用就是继承。

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
</project>

(1)packaging 必须设置为 pom。

同时,在各个子Maven项目中,也要指向该父 Maven 项目,以account-email为例:

<project>
    <modelVersion>4.0.0</modelVersion>
   
    <parent>
        <groupId>com.juvenxu.mvnbook.account</groupId>
        <artifactId>account-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../account-parent/pom.xml</relativePath>
    </parent>
   
    <artifactId>account-email</artifactId>
    <name>Account Email</name>
</project>

(1)parent 使用parent元素声明父模块,groupId + artifactId + version 唯一定位父模块。
(2)relativePath 指定父模块pom.xml文件的相对路径。这个设置很重要,如果找不到父模块的pom.xml,子Maven项目将构建失败。
(3)在子Maven项目中不再声明 groupId 和 version,因为已经从父模块中继承了。当然,如果子Maven 项目中的groupId 和 version 与父模块中的声明不同,也可以继续声明,覆盖父模块中的声明。

最后,在 account-aggregator 项目中还要增加 account-parent 模块。

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
    <modules>
        <module>account-parent</module>
        <module>account-email</module>
        <module>account-persist</module>
    </modules>
</project>

完成后的项目目录结构如下:
account-aggregator
    -- account-email
        -- pom.xml
        ...
    -- account-persist
        -- pom.xml
        ...
    -- account-parent
        -- pom.xml
    -- pom.xml

3. 其它可继承的POM元素
除了 groupId 和 version,还有很多元素可以继承,其中最重要的是依赖关系:dependencies。
直接把dependicies加到父Maven项目中是可以的,但是还不够灵活,因为不是每个子Maven项目都需要这些依赖。
dependencyManagement 既可以让子模块继承到父模块的以来配置,又能保证子模块依赖使用的灵活性。
在dependencyManagement中声明的依赖不会引入实际的依赖,但是可以约束dependencies的使用。
如果子模块不声明依赖的使用,即使该依赖在父模块的 dependencyManagement 中声明了,还是不会起作用。
要引入实际的依赖,还是要在dependencies元素中定义才有效。

在父Maven项目:account-parent 中加入 dependencyManagement 配置信息:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
    <properties>
        <springframework.version>2.5.6</springframework.version>
        <junit.version>4.7</junit.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

此时,在子Maven项目:account-email 中的依赖配置如下:

<project>
    <modelVersion>4.0.0</modelVersion>
   
    <parent>
        <groupId>com.juvenxu.mvnbook.account</groupId>
        <artifactId>account-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../account-parent/pom.xml</relativePath>
    </parent>
   
    <artifactId>account-email</artifactId>
    <name>Account Email</name>

    <properties>
        <javax.mail.version>1.4.1</javax.mail.version>
        <greenmail.version>1.3.1b</greenmail.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>       
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>           
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>           
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>           
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>${javax.mail.version}</version>
        </dependency>       
        <dependency>
            <groupId>com.icegreen</groupId>
            <artifactId>greenmail</artifactId>
            <version>${greenmail.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

(1)子Maven项目中的依赖只需定义groupId 和 artifactId,因为version 和 scope 已经从父Maven项目中继承了,从而保证所有子Maven项目使用的依赖是同一个版本,降低依赖冲突。
(2)子Maven项目中可以继续详细定义没有在父Maven项目中定义的依赖。
(3)在子Maven项目中不再声明 groupId 和 version,因为已经从父模块中继承了。
当然,如果子Maven 项目中的groupId 和 version 与父模块中的声明不同,也可以继续声明,覆盖父模块中的声明。

4. 导入 dependencyManagement 中声明的依赖
还记得依赖关系中有个import的scope吧,这个范围的依赖只在 dependencyManagement 元素中才有意义。

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.juvenxu.mvnbook.account</groupId>
                <artifactId>account-parent</artifactId>
                <version>1.0.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>          
        </dependencies>
</dependencyManagement>

(1)导入account-parent 模块中定义的dependencyManagement 内容。
(2)如果有多个项目使用的依赖版本都是一致的,则可以定义一个使用 dependencyManagement 专门管理依赖的POM,然后在各个项目中导入这个依赖。

5. 使用 pluginManagement 管理插件
与 dependencyManagement 使用方法类似,Maven使用pluginManagement 管理插件。
在父模块中声明可以使用的插件,在子模块中声明要使用的插件。

参考文献:
1. 《Maven 实战》 徐晓斌著

2015年12月26日星期六

Maven_003:设置本地仓库和远程仓库

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

构件在仓库中的路径为: groupId/artifactId/version/artifactId-version-classifier.packaging。

Maven仓库分为本地仓库和远程仓库这两种,首先从本地仓库去找构件,如果存在,则直接使用;如果不存在,去远程仓库查找,找到后,下载到本地仓库。
如果本地仓库和远程仓库都没有找到需要的构件,Maven会报错。
中央仓库Maven核心自带的远程仓库,默认情况下,当本地仓库没有构件的时候,就会从中央仓库下载。
私服是一种特殊的远程仓库,是假设在局域网内的私有仓库,用其代理所有的远程仓库。
除了中央仓库和私服,还有很多其它公开的远程仓库,比如JBoss Maven 库:http://repository.jboss.org/maven2/。

1. 设置本地仓库
默认情况下,本地仓库指向~/.m2/repository目录。
要指向其它目录,需要修改~/.m2/settings.xml文件,增加如下内容:
<!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
-->

2. 私服
私服是指在局域网内部搭建的 repository,它跟 central repository,jboss repository等的区别仅仅在于其 URL 是一个内部网址。

3. 设置远程仓库
远程仓库既可以设置在pom.xml中,也可以设置在settings.xml文件中。

 <project>
    ...
    <repositories>
        <repository>
          <id>jdk14</id>
          <name>Repository for JDK 1.4 builds</name>
          <url>http://www.myhost.com/maven/jdk14</url>
          <layout>default</layout>
          <snapshotPolicy>always</snapshotPolicy>
        </repository>
    </repositories>
    ...
 </project>

(1)仓库的id必须唯一。
(2)releases的enable值为true,表示开启发布版本的下载支持。
(3)snapshots的enable值为false,表示关闭快照版本的下载支持。
(4)layout 表示使用Maven 2 或 3 的布局。
(5)updatePolicy 表示从远程仓库的更新频率,默认是daily,每天检查;never,从不检查;always,每次构建都检查更新;X,每隔X分钟检查一次。
(6)checksumPolicy 表示部署构件时,会同时部署对应的校验文件;下载构件时,会验证校验文件。该值为 warn 时,提示警告;为 fail 时,构建失败;为 ignore 时,忽略错误。 

4. 配置远程仓库的认证
远程仓库的认证只能设置在settings.xml文件中。

<servers>
    <!-- server
     | Specifies the authentication information to use when connecting to a particular server, identified by
     | a unique name within the system (referred to by the 'id' attribute below).
     |
     | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
     |       used together.
     |
    <server>
      <id>deploymentRepo</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    -->

    <!-- Another sample, using keys to authenticate.
    <server>
      <id>siteServer</id>
      <privateKey>/path/to/private/key</privateKey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    -->
</servers>

5. 部署构件到远程仓库
在pom.xml中设置远程仓库:

<distributionManagement>
    <repository>
        <id>releases</id>
        <name>Nexus Release Repository</name>
        <url>http://localhost:8081/nexus/content/repositories/releases/</url>
    </repository>
    <snapshotRepository>
        <id>snapshots</id>
        <name>Nexus Snapshot Repository</name>
        <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
    </snapshotRepository>
</distributionManagement>

(1)releases 是发布版本的构件,项目外部的依赖应该都是发布版本的构件。
(2)snapshots 是快照版本的构件,快照版本的构件只应该用于项目内部的模块依赖。
(3)repository 中的 id 必须与 server 中的 id 一致。

运行 mvn clean deploy,部署构件到远程仓库,发布版本会部署到发布版本的远程仓库;快照版本会部署到快照版本的远程仓库。

6. 镜像
仓库 X 能够提供仓库 Y 的所有内容,那么仓库 X 就是仓库 Y 的一个镜像。
配置镜像后,本来需要从仓库 Y 下载构件的请求会转到仓库 X。
在 settings.xml 中增加镜像的配置:

例1:指定仓库的镜像
<mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->
</mirrors>
说明:
(1)mirrorOf 指定镜像的repositoryId。也可以以逗号间隔,指定多个远程库。

例2:中央仓库的镜像
<settings>
  ...
  <mirrors>
    <mirror>
      <id>maven.net.cn</id>
      <name>one of the central mirrors in china</name>
      <url>http://maven.net.cn/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
  ...
</settings>
说明:
(1)mirrorOf 指定镜像的repositoryId,这里 central 表示中央仓库。也可以以逗号间隔,指定多个远程库。

例3:所有仓库的镜像
关于镜像的一个更为常见的用法是结合私服。由于私服可以代理任何外部的公共仓库,因此,对于组织内部的 Maven 用户来说,使用一个私服地址就等于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化 Maven 本身的配置。在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像。  

<settings>
  ...
  <mirrors>
    <mirror>
      <id>internal-repository</id>
      <name>Internal Repository Manager</name>
      <url>http://192.168.1.100/maven2</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors>
  ...
</settings>

说明:
(1) <mirrorOf>*</mirrorOf> ,表示该配置是所有 Maven 仓库的镜像,任何对于远程仓库的请求都会被转至 http://192.168.1.100/maven2/。
如果该镜像仓库需要认证,则配置一个 id 为 internal-repository 的 <server> 即可。
(2) <mirrorOf>external:*</mirrorOf> ,表示匹配所有远程仓库,使用localhost 的除外,使用 file:// 协议的除外。也就是说,匹配所有不在本机上的远程仓库。
(3) <mirrorOf>repo1,repo2</mirrorOf> ,表示匹配仓库 repo1 和 repo2,使用逗号分隔多个远程仓库。 
(4) <mirrorOf>*,!repo1</miiroOf> ,表示匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。

需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven 将无法访问被镜像仓库,因此也将无法下载构件。

7. 私服与镜像的区别
私服本身是一个 repository,可以和其它 repository 一起提供服务,比如它可以用来提供公司内部的 maven 构件。
镜像相当于一个代理,它会拦截去指定的远程 repository 下载构件的请求,然后从自己这里找出构件回送给客户端。镜像本身并不是 repository,它只是远程 repository 的网络加速器,配置镜像的目的一般是出于网速考虑。

可以看出,私服和镜像两个不同的东西。
不过很多私服搭建工具本身也提供镜像服务,比如 Nexus 就可以让同一个 URL 既用作internal repository,又使它成为所有 repository 的 mirror。

参考文献:
1. 《Maven 实战》 徐晓斌著

2015年12月25日星期五

Maven_002:构建项目

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. pom.xml

Maven项目的核心是pom.xml文件,POM(Project Object Model)定义了项目的基本信息,描述了项目如何构建,声明了项目的依赖关系,等等。
下面是一个helloworld的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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>helloworld</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Hello World</name>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

(1)modelVersion 指定了当前POM的版本,对于Maven 3 来说,该值只能是4.0.0。
(2)groupId 指定了项目所属的组,一般为某个公司名称或组织名称 + 项目名称,表明当前项目隶属的实际项目,比如org.sonatype.nexus。
(3)artifactId 指定了项目在该组中的唯一标识,一般为实际项目中的一个Maven项目,推荐使用实际的项目名称作为前缀,比如nexus-indexer。
注意,Maven项目和实际项目不一定是一对一的关系,很多实际项目可能对应很多Maven项目。
(4)version 指定了项目的版本。
(5)name 指定了项目的名称,该项不是必须的,但为了可读友好性,还是建议加上该项。
(6)packaging 指定了Maven项目的打包方式,比如 jar(默认方式),war。
(7)calssfier 指定了输出的附属构件,比如 javadoc、sources。附属构件不是项目默认生成的,需要配置相应的插件才可以。

groupId + artifactId + version 定义了一个项目的基本的x、y、z坐标,每一个Maven项目都可以通过这三个坐标来彼此区分。

所有的Maven项目都隐式地继承一个超级POM,对于Maven 3,该文件位于 $MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml。

2. 项目依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.7</version>
        <scope>test</scope>
    </dependency>
</dependencies>

(1)dependencies 里面可以有多个 dependency,表示项目的依赖。
(2)scope 为依赖范围:
compile(默认选项)表示该依赖对编译、测试、运行的 classpath 都有效,比如 spring-core;
test 表示该依赖只对测试的 classpath 有效,比如 JUnit;
provided  表示该依赖对编译、测试的 classpath 都有效,对运行的 classpath 无效,比如 servlet-api,在编译和测试时需要该依赖,在运行时,因为容器已经提供,因此就不需要了;
runtime 表示该依赖对测试、运行的 classpath 都有效,对编译的 classpath 无效,比如 JDBC驱动,编译时只需要标准的JDBC接口API即可,测试和运行时才需要具体的JDBC驱动;
system 与 provided 方式的依赖一样,只不过指定依赖时,必须通过systemPath显式指定,往往与本机系统绑定,造成不可移植,应慎用。
import 导入依赖范围,该依赖不会对编译、测试、运行的 classpath 有任何实际的影响。
(3)optional
(4)exclusions

关于依赖,还有很多概念需要了解,比如传递性依赖、依赖调解、可选依赖、排除依赖、归类依赖等等,留待以后专文阐述。

要想查看一个Maven项目的依赖,可以运行 mvn:dependency:list 或 mvn:dependency:tree 或 mvn:dependency:analyze。

2. 编译、测试、打包、安装
 (1)mvn clean compile
 (2)mvn clean test
 (3)mvn clean package
该命令会在 target 目录下生成 artifactId + version.jar 文件,也可能是其它类型的文件,比如war文件。
 (4)mvn clean install
为了让其它Maven 项目能够引用该 jar,需要运行该命令将该Maven项目安装到本地库。

3.  使用maven-shade-plugin
我们知道如果要运行.jar中的某个带有Main函数的类,需要在META-INFO目录中创建MANIFEST.MF文件。
文件内容要增加一行:Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld。
手工增加太麻烦了,为此使用 Maven 插件:maven-shade-plugin。
<plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <source>1.5</source>
            <target>1.5</target>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>1.2.1</version>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>shade</goal>
              </goals>
              <configuration>
                <transformers>
                  <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                    <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>
                  </transformer>
                </transformers>
              </configuration>
            </execution>
          </executions>
        </plugin>
</plugins>

使用 maven-compiler-plugin 的目的是为了支持JDK 1.5。

4. 使用 mvn archetype:generate 生成Maven项目骨架 
运行后,将会以交互的方式生成一个Maven项目,目前有1497个Maven项目骨架。
首先输入骨架对应的数字,默认是704,Maven的quickstart项目骨架。
接着输入 groupId、artifactId、version 等值,生成Maven项目。
常用的Maven骨架有maven-archetype-quickstart (Java Project, JAR)、maven-archetype-webapp (Java Web Project, WAR)等等。

5. 使用 mvn archetype:crawl 生成骨架目录文件
1497个Maven骨架太多了,而且不知道选择哪个,可以把所有内容写到一个文件中,然后慢慢查找。
mvn archetype:generate > templates.txt

也可以生成 archetype-catalog 目录,因为实际使用中常用的就是那几个。
运行 mvn archetype:crawl 后,会在~/.m2/responsitory目录下生成archetype-catalog.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-catalog xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0 http://maven.apache.org/xsd/archetype-catalog-1.0.0.xsd"
    xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <archetypes>
    <archetype>
      <groupId>org.apache.maven.archetypes</groupId>
      <artifactId>maven-archetype-quickstart</artifactId>
      <version>1.1</version>
      <description>quickstart</description>
    </archetype>
  </archetypes>
</archetype-catalog>

把 archetype-catalog.xml 移动到~/.m2目录下。
运行 mvn archetype:generate -DarchetypeCatalog=local,此时只会显示archetype-catalog.xml文件中的骨架。

另外,也可以运行 mvn archetype:generate -DarchetypeCatalog=internal,此时会显示10个内部骨架。

6. 约定优于配置
Maven 的默认约定如下:
(1)源码目录为:src/main/java
(2)编译输出目录为:target/classes
(3)打包方式为:jar
(4)包输出的目录为:target

参考文献:
1. 《Maven 实战》 徐晓斌著
2.  http://www.cnblogs.com/buhaiqing/archive/2012/11/04/2754187.html

Maven_001:下载与安装配置

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. 下载 http://maven.apache.org/

2. 安装 unzip apache-maven-3.3.9-bin.zip

3. 配置
(1)ln -s apache-maven-3.3.9 maven
(2)环境变量脚本

#!/bin/sh

#Set Java Environment
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar
export ANT_HOME=/Users/maping/Apache/ant
export MAVEN_HOME=/Users/maping/Apache/maven
export M2_HOME=/Users/maping/Apache/maven
export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$M2_HOME/bin:$MAVEN_HOME/bin:$PATH

说明:
MAVEN_HOME 用于 Maven 1.x,M2_HOME 用于 Maven 2.x 和 3.x。

(3)修改Maven使用的内存
Maven运行时,实际是调用的Java,因此设置内存方式和Java一样。

export MAVEN_OPTS= -Xms128m -Xmx512m

(4)为了保证使用同一个Maven,IDE也不要使用自带的Maven,而是指向同一个MAVEN_HOME。
这里以NetBeans为例说明:



4. 执行 mvn -v,确认安装配置正确。
也可以运行 mvn help:system,查看本地环境。

5. 全局性配置文件:setttings.xml
在conf目录下有一个非常重要的文件:setttings.xml,该文件是Maven的全局性配置文件,所有该机器上的用户都会受到此文件的影响。
一般情况下,我们不修改该位置的settings.xml文件,而是复制该文件到~/.m2/目录下后,修改该文件,在用户的范围内定制Maven的行为。

6. Maven本地仓库
在~/.m2/目录下有一个repository目录,该目录就是该用户的Maven本地仓库。

7. 设置代理
如果无法直接访问Maven 中央库,可以设置代理,步骤如下:
(1)确认是否能够访问中央库:ping repo1.maven.org
(2)确认是否能够访问代理:telnet
(3)编辑~/.m2/settings.xml,增加如下内容:

  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
    -->
  </proxies>

proxies中可以包含多个proxy,第一个被激活( <active>true</active>)的proxy将被使用。
nonProxyHosts 指定哪些主机名不需要代理,支持通配符,比如:*.google.com。

8. 查看本地环境
运行 mvn help:system

参考文献:
1. 《Maven 实战》 徐晓斌著

JDG_014:缓存节点规划以及容量估算

假定每个JDG节点的堆内存容量估算后的大小为H,那么其推算过程如下:

1. 期望每个JDG节点的堆内存大小是多少?(变量=>S)

2. 估算一条数据的长度。(变量=>x)
  (1)x = 序列化后的Key + 序列化后的Value + 200 bytes 元数据

3. 期望多少条数据放入缓存中?(变量=>y)

4. 考虑到数据同步与计算的冗余,需要给堆内存留出一部分“空闲”空间。(变量=>p,默认0.5)

5. 部署模式是哪种?Local,Distributed,还是 Replicated mode?
    (1)如果是 Local 或 Replicated mode,那么 H = (x * y) / p,这里 S 必须大于 H。
    (2)如果是 Distributed mode,owners=n(变量=>n),那么1份数据需要的JDG节点数是 (x * y) / (S * p) + 1,n份数据需要的JDG节点数是 ((x * y) / (S * p) + 1) * n。

现在我们根据真实使用案例,实际推算一下。
(1)S = 32 G
(2)x = 10 + 35 + 200 = 245 bytes
(3)y = 1,000,000,000 (10 亿条)
(4)p = 0.5
(5)Distributed mode,owners = 3

数据总量是 245 * 1000000000 = 245 G
每个JDG节点可用来存储数据的内存 = 32 * 0.5 = 16 G
1份数据需要的JDG节点数= ((245 * 1) / (32 * 0.5) + 1) = 16
3份数据需要的JDG节点数= ((245 * 1) / (32 * 0.5) + 1) * 3 = 48

参考文献:
1. https://mojo.redhat.com/docs/DOC-174679

2015年12月18日星期五

JDG_013:JDG CLI 使用指南

环境:MAC OS 10.10.5 + JDG 6.5.1

进入 jboss-datagrid-6.5.1-server/bin 目录,

1. ./jboss-cli.sh --connect=jmx://127.0.0.1:10099
默认端口是9999,这里端口偏移了100,变成10099。
如果连接成功,会自动进入当前cache所在的cache-container,比如我这里是clustered。
[standalone@127.0.0.1:10099 cache-container=clustered]

2.  在[standalone@127.0.0.1:10099 cache-container=clustered] 处按“Tab”键,会显示能做的操作
(1)输入container,会显示有哪些cache-container。
(2)输入cache + “Tab”键,会显示有哪些cache,比如我这里会显示:
          TRANSPORT       default         labCache        memcachedCache  namedCache
(3)输入cache labCache,进入labCache:[standalone@127.0.0.1:10099 distributed-cache=labCache]
(4)输入stats,显示当前cache的统计信息

[standalone@127.0.0.1:10099 distributed-cache=labCache] stats
Statistics: {
  hits: 0
  evictions: 0
  hitRatio: 0.0
  removeHits: 0
  readWriteRatio: 0.0
  misses: 0
  averageRemoveTime: 0
  averageReadTime: 0
  numberOfEntries: 67
  averageWriteTime: 1
  statisticsEnabled: true
  elapsedTime: 58461
  removeMisses: 0
  stores: 65
  timeSinceReset: 58461
}
LockManager: {
  numberOfLocksAvailable: 0
  numberOfLocksHeld: 0
  concurrencyLevel: 1000
}
RpcManager: {
  committedViewAsString: [jdg-2/clustered, jdg-1/clustered, jdg-3/clustered]
  statisticsEnabled: true
  replicationFailures: 0
  successRatioFloatingPoint: 1.0
  replicationCount: 42
  averageReplicationTime: 2
  successRatio: 100%
  pendingViewAsString: null
}

(5)输入put 1 1,插入一条数据。
(6)输入get 1,显示刚插入的数据。
(7)输入encoding --list,显示都有哪些encoding。
memcached
hotrod
none
rest
(8)输入get --codec=hotrod 1,显示程序插入的Value。

参考文献:
1. https://docs.jboss.org/author/display/ISPN/Command-Line+Interface+%28CLI%29

2015年12月16日星期三

JDG_012:JDG Demo 演示:jdg-visualizer

环境:MAC OS 10.10.5 + JDG 6.5.1 + JBoss EAP 6.4.0

jdg-visualizer 可以监控JDG集群中各个节点的数据数量分布情况。

1. 下载 jdg-visualizer
下载地址:https://github.com/infinispan/visual

2. 下载 hotrod-demo
hotrod-demo 可以向集群中某个节点插入数据,从而导致整个集群的数据重新分布。
下载地址:https://github.com/saturnism/hotrod-demo/

3. 编译 jdg-visualizer
mvn clean package
编译成功后会生成 jdg-vistualizer.war 文件。

4. 编译 hotrod-demo
mvn clean package
编译成功后会生成 hotrod-demo-0.0.2-SNAPSHOT-jar-with-dependencies.jar 文件。

5. 配置并启动JDG集群
(1)unzip jboss-datagrid-6.5.1-server.zip
(2)执行./add-user.sh,增加管理员用户 admin/welcome@1
(3)mkdir jdg-visualizer-node1
(4)cp -r ./jboss-datagrid-6.5.1-server/standalone jdg-visualizer-node1
(5)mkdir jdg-visualizer-node2
(6)cp -r ./jboss-datagrid-6.5.1-server/standalone jdg-visualizer-node2
(7)mkdir jdg-visualizer-node3
(8)cp -r ./jboss-datagrid-6.5.1-server/standalone jdg-visualizer-node3
(9)./clustered.sh -Djboss.server.base.dir=/Users/maping/Redhat/datagrid/jdg-visualizer-node1/standalone -c clustered-jdg-visualizer.xml -b 127.0.0.1 -bmanagement=127.0.0.1 -Djboss.node.name=jdg-1 -Djboss.socket.binding.port-offset=100
(10)./clustered.sh -Djboss.server.base.dir=/Users/maping/Redhat/datagrid/jdg-visualizer-node2/standalone -c clustered-jdg-visualizer.xml -b 127.0.0.1 -bmanagement=127.0.0.1 -Djboss.node.name=jdg-2 -Djboss.socket.binding.port-offset=200
(13)./clustered.sh -Djboss.server.base.dir=/Users/maping/Redhat/datagrid/jdg-visualizer-node3/standalone -c clustered-jdg-visualizer.xml -b 127.0.0.1 -bmanagement=127.0.0.1 -Djboss.node.name=jdg-3 -Djboss.socket.binding.port-offset=300
(14)其中 clustered-jdg-visualizer.xml 配置如下(分布式模式,并使用tcp):
 <distributed-cache name="labCache" mode="SYNC" owners="2" remote-timeout="30000" start="EAGER">
    <locking isolation="READ_COMMITTED" acquire-timeout="30000" concurrency-level="1000" striping="false"/>
    <transaction mode="NONE"/>
 </distributed-cache>

 6. 部署 jdg-visualizer.war 到 EAP,并启动EAP
 (1)./standalone.sh -b 127.0.0.1 -bmanagement=127.0.0.1 -Djdg.visualizer.jmxUser=admin -Djdg.visualizer.jmxPass=welcome@1 -Djdg.visualizer.serverList=localhost:11322
注意这里要设置连接到某个JDG节点的JMX用户名和口令,就是之前配置JDG时设置的。
只要连接到其中一个JDG节点即可,EAP会自动发现集群中的其它节点。

7. 访问 http://localhost:8080/jdg-visualizer/
 (1)没有任何数据的情况下,是这个样子的:


 (2)向某个JDG节点插入数据,运行
java -Djdg.demo.initialList=localhost:11322 -Djdg.demo.cacheName=labCache -Djdg.demo.maxEntries=100 -Djdg.demo.clearOnFinish=false -Djdg.demo.putDelay=0 -Djdg.demo.useTwitter=false -jar hotrod-demo-0.0.2-SNAPSHOT-jar-with-dependencies.jar


 (3)停掉一个节点

 (4)再停掉一个节点

参考文献:
1. https://github.com/infinispan/visual
2. https://github.com/saturnism/hotrod-demo/