Written by Srikanth Shenoy November 2003
Translated by jinfeng wang 2005年三月
原文地址:http://www.theserverside.com/articles/article.tss?l=MavenMagic
本文的翻译已经原作者同意,转载请保持原文。如有问题和意见可以和原作者或我联系。
Part 1: http://www.blogjava.net/jinfeng_wang/archive/2005/03/11/1956.html
Part 2: http://www.blogjava.net/jinfeng_wang/archive/2005/03/14/2074.html
Now I will show you how to use the XDoclet plugin to generate the tld automatically. I will be using XDoclet version 1.2 Beta3. Consider the declaration in the tld file for a tag say MyTag.
下面我将演示XDoclet是如何自动生成tld文件的。我将使用XDoclet的1.2 Beta3版本。这里假设将在tld文件中声明MyTag的tag。
<tag>
<name>mystuff</name>
<tag-class>foobar.webapp.MyTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>locale</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
It is okay to have a readymade tld for frameworks such as Struts. However when you are developing your own tags either by customizing the existing tags or from scratch, it is natural that they change and evolve constantly during development. It can be time consuming to manually synchronize the tag code and its declaration in the tld. XDoclet is designed to ease such burdens. In the source code for the MyAppTag, add @jsp.tag name="myapptag" body-content="JSP" in its class comments section. For each of the tag attributes, add a @jsp.attribute on the getter method for that attribute. For instance, add @jsp.attribute required="false" rtexprvalue="false" to the comments on the getMyMessage method to represent that myMessage is a tag attribute. Next you invoke the webdoclet goal from the xdoclet plugin in maven.xml as shown in Listing 12. XDoclet also gives you provision to generate the web.xml too. Let us look at the maven.xml for the Web project in its entirety.
在项目中使用现有的诸如Structs的tld框架是可以的,但是有时候通过定制现有tag或者完全重写的方式,开发自己的tag,显然在开发的过程中他们会经常的变化。手工保持tag代码和tld文件中声明的同步是非常耗时的,XDoclet则可以帮你减轻这里的工作。在MyAppTag的源代码中,在class的注释部分加入@jsp.tag name="myapptag" body-content="JSP"。对于每一个tag属性,请在属性的getter方法前面前添加@jsp.attribute。例如在表示myMessage是tag属性的getMyMessage方法的前面加入@jsp.attribute required="false" rtexprvalue="false"。下面将会如表12所示在maven.xml中调用xdoclet插件的webdoclet方法。XDoclet页可以帮你生成web.xml,我们来看看Web项目中的完整的maven.xml吧。
Listing 12 maven.xml for the Web Project
表12 Web项目的maven.xml
<project default="foobar-dist" xmlns:m="jelly:maven"
xmlns:ant="jelly:ant">
<goal name="foobar-dist">
<attainGoal name="war:install" />
</goal>
<preGoal name="war:init">
<attainGoal name="xdoclet:webdoclet"/>
</preGoal>
</project>
NOTE: You have to add the XDoclet web module in the dependency section for the project.xml as follows. 注意:你必须在project.xml的依赖部分如下加入XDoclet的Web module(译者注:源代码中有问题,在我的系统中需要写成“<artifactId>xdoclet-web-module</artifactId>”,此外,还有些其他问题。): <dependency>
In addition, override the following properties in the plugin.properties file for XDoclet under the Maven plugins folder 另外,在Maven的插件目录中找到XDoclet,如下修改plugin.properties的属性: maven.xdoclet.webdoclet.deploymentdescriptor.0=false The first setting disables web.xml generation and the second setting sets the generated tld file location. In this article you will just be generating the tld file, but not generating the web.xml, nor the <taglib> entry for the tld file in web.xml. As a matter of fact, XDoclet does not seem to have the Maven equivalent for the following Ant script that adds the <taglib> to web.xml. 这里第一个设置禁止了Web.xml的自动生成,第二个设置了tld文件生成位置。在本文中,你将会生成tld文件,但是并不需要生成Web.xml,也不许在web.xml中添加<taglib>入口。事实上,XDoclet好像没有Ant中将<taglib>加入到web.xml中的功能,Ant的代码可以这样写: <deploymentdescriptor servletspec="2.3" destdir="${WEBINF}" >
Another thing that I noticed in the XDoclet plugin is that the file name for the tag library definitions (tld) has to be provided in plugin.properties as follows. 我还注意到:在Xdoclet插件中,tld文件名必须在plugin.properties中如下给出: maven.xdoclet.webdoclet.jsptaglib.0.filename=myapp.tld
Otherwise the tld file is generated with the default name of taglib.tld. This does not seem right. Instead it should be set in the build script. For instance, in Ant this is done as follows 否则tld文件名将会是默认的taglib.tld,这是不正确的。它应该在build脚本中被设置。在Ant中则是这样写: <jsptaglib jspversion="1.2" destdir="${WEBINF}/tld" Ideally I would like to set this like this: 我更喜欢下面的比较完美的写法: <dependency> This is not a Maven defect. It just is an example showing that it takes time for third party vendors to catch up. 这并不是Maven的缺点,它是第三方插件提供者所需要注意的问题。 |
Building the EAR (构建EAR)
Up until now you have seen how to create each of the individual artifacts that go into the EAR. Finally we have reached the last part - building the EAR itself. You might imagine that since the EAR is the only artifact from the project as a whole, it should be built from the project definition at the top of the hierarchy, i.e. the Foobar-Travels folder. However that is not the case. The EAR is built as an artifact from a subproject called ear (See Figure 3). Why this anomaly? First of all, the project.xml at the Foobar-Travels project level is a template for other subprojects to extend. If it were to specify the dependencies to build the EAR, then it would have resulted in a cyclic dependency - a chicken and egg situation - when the template is extended by other subprojects. If the template were to be defined elsewhere, probably at the organization level, then the project.xml in Foobar-Travels folder could have produced the EAR but then it would not be the template for the rest of the subprojects to extend.
到目前为止,你已经了解了如何创建各将要加入到EAR中的制品,现在我们开始最后一步-构建EAR。也许你会这样的想法:因为EAR是做为整个项目的唯一制品,那么就该在项目的最顶端构建它,例如Foobar-Travels目录。但是事实上却不是这样的。EAR是做为一个单独的子项目的制品被生成的(参考图3)。为何这样特别呢?首先,Foobar-Travels项目的顶层project.xml是作为各子项目的模板进行扩展的。如果在其中声明了EAR所依赖的包,那么在模板被其他子项目扩展的时候,就会陷入循环依赖的困境(鸡和蛋,谁先有?)。如果模板在其它进行声明,例如在组织级别,那么Foobar-Travels目录中的project.xml可以用于构建EAR,但是该文件就再也无法作为子项目的模板使用了。
Listing 13 shows the project.xml for the ear project. In the listing, you will not see every library on which the ear is dependent upon, just a few relevant ones that need some explanation.
表13给出了ear项目的project.xml。在此表中,并没有列出ear项目所依赖的所有包,这里仅列出了需要解释的相关内容。
Listing 13 project.xml for the ear project
表13 ear项目的project.xml
01 <project>
02 <extend>${basedir}/../project.xml</extend>
03 <id>foobar-travels</id>
04 <name>Foobar EAR</name>
05 <description>Sample EAR project.</description>
06 <shortDescription>Foobar EAR project</shortDescription>
07 <dependencies>
08 <dependency>
09 <groupId>j2ee</groupId>
10 <artifactId>j2ee</artifactId>
11 <version>1.3.1</version>
12 </dependency>
13 <dependency>
14 <groupId>xerces</groupId>
15 <artifactId>xerces</artifactId>
16 <version>1.4.4</version>
17 <properties>
18 <ear.bundle>true</ear.bundle>
19 </properties>
20 </dependency>
21 <dependency>
22 <groupId>${pom.groupId}</groupId>
23 <artifactId>reservationejb</artifactId>
24 <version>${pom.currentVersion}</version>
25 <type>ejb</type>
26 <properties>
27 <ear.bundle>true</ear.bundle>
28 </properties>
29 </dependency>
30 <dependency>
31 <groupId>${pom.groupId}</groupId>
32 <artifactId>foobar-web</artifactId>
33 <version>${pom.currentVersion}</version>
34 <type>war</type>
35 <properties>
36 <ear.bundle>true</ear.bundle>
37 <ear.appxml.ear.context-root>
38 foobar-online
39 </ear.appxml.ear.context-root>
40 </properties>
41 </dependency>
42 </dependencies>
43 </project>
- Line 25 Type = ejb indicates that this is a ejb jar, This is set in application.xml
- Line 34 Type = war indicates that this is a war, This is set in application.xml
- Lines 37-39 Sets the context root for the web application, This is set in application.xml .
- 第25行:“Type = ejb”表示这是ejb jar,这将在application.xml中设置。
- 第25行:“Type = war”表示这是war,这将在application.xml中设置。
- 第37-39行:为web应用设置context-root,这将在application.xml中设置。
The first dependency that you will find is on J2EE itself. This library is not bundled since the container at runtime provides it. The second dependency is on the xerces xml library - a representative of the dependency library (including our very own services jar). Libraries such as these may not be provided by the application server and have to be bundled with the ear. Then comes the ejb jar itself. The type=ejb sets the application.xml appropriately. Similarly, the web application is bundled by specifying the dependency and type=war. The above project definition automatically creates application.xml for the ear. By using ear:install as the goal, the ear is also copied into the maven repository. The generated application.xml is shown in Listing 14. Obviously, setting the type has had its effect. Also note the web application context-root setting. The short description from the project.xml is used as the display name for the EAR. When Maven starts the execution of project.xml for the EAR it sees the dependencies and then proceeds to create the artifacts for the dependencies before creating the EAR itself.
你会发现它依赖的第一项内容是J2EE本身,由于容器会在运行的时候提供此包,所以无需将其打包。第二项内容是xerces xml包,它是依赖包的代表(译者注:因为表13中仅列出了一部分内容,这里将xerces xml包做为代表列出)。由于应用服务器可能并不提供这样的依赖包,所以必须将它打入到EAR中。随后的是ejb jar,“type=ejb”将会使得其在application.xml中正确设置。同样,Web程序也要打包到EAR中,并说明“type=war”。因为使用ear:install,所以EAR也会被拷贝到仓库中。生成的Application.xml文件如表14所示。显然前面的type的设置在application.xml中起到作用了。同时,请注意web application 的context-root的设置。project.xml中的short description部分将会被用作EAR显示名。当Maven为EAR开始执行project.xml时,它将观察其所依赖的各包,并在创建EAR包之前,逐一的生成各依赖包。
Listing 14 Generated application.xml
表14 生成的application.xml文件
<application>
<display-name>Foobar EAR project</display-name>
<module>
<java>xerces-logging-1.4.4.jar</java>
</module>
<module>
<ejb>reservationejb-2.0.jar</ejb>
</module>
<module>
<web>
<web-uri>foobar-web-2.0.war</web-uri>
<context-root>foobar-online</context-root>
</web>
</module>
</application>
We haven't looked at the maven.xml for the EAR project yet. It turns out to be quite trivial in that it just executes the ear:install goal.
我们还没看过EAR项目的Maven.xml呢,它的内容很短小,只是执行ear:install goal。
<project default="foobar-dist">
<goal name="foobar-dist">
<attainGoal="ear:install"/>
</goal>
</project>
Another file that you need to provide is project.properties. By default auto-generation of application.xml is turned off. To force auto-generation, you can set the property in project.properties as follows,and place the file in the ear folder under Foobar-Travels directory.
此外,还需要提供一个project.properties文件。在默认情况下,是无法自动生成application.xml的,因此你需要在project.properties文件中如下设置属性,才能强制自动生成application.xml,并将其存放到Foobar-Travels中的ear目录下。
maven.ear.appxml.generate=true
Using the reactor(使用reactor)
We have covered all the files in building a J2EE project, except one. This file that we have been intentionally postponing till the end is the maven.xml that accompanies the master project template. In the last subsection on building EAR, I stated "When Maven starts the execution of project.xml for the EAR it sees the dependencies and then proceeds to create the artifacts for the dependencies before creating the EAR itself". I lied! This is not completely true. The project definition for EAR is just like any other project.xml. For every dependency stated in that file, it will search the maven repository for the appropriate jar file. What this means is that you will have to run maven individually from dependency library projects, ejb projects, web application projects and finally the ear project in that order to execute jar:install, ejb:install, war:install and ear:install respectively. Now, that can be too cumbersome if not impossible in a large project. Maven offers the reactor as a solution to this problem.
我们已将构建J2EE项目的所有内容基本讲完了,最后还有一项内容,它就是我们故意延迟讲述的和主项目模板一起的maven.xml文件。在构建EAR的最后一段,我是这样讲的“当Maven为EAR开始执行project.xml时,它将观察其所依赖的各包,并在创建EAR包之前,逐一的生成各依赖包。”。哈,我刚撒谎了,这并不是真的。EAR的project.xml的定义和其他项目是一样的。在project.xml中,只给出每一个依赖,然后maven将会在仓库中搜索相应的jar包。这就意味着:你必须自己单独的为每个子项目运行Maven,包括依赖包项目(services)、Ejb项目、Web项目、以及Ear项目。你必须在每个项目下分别运行jar:install, ejb:install, war:install and ear:install才能完成任务。如果在大的项目中也是如此,那就相当让人麻烦了。Maven提供了reactor解决此问题。
Reactor is a tool for executing dependent multi-project builds. Given a set of project.xmls, the reactor determines the correct order of execution based on the dependencies listed in the respective project.xmls. More news: The reactor can be declared using Jelly scripts in the maven.xml file itself. This is what we will have in the maven.xml accompanying the master project template. The maven.xml in the Foobar-Travels folder (See Figure 3) is shown in Listing 15.
Reactor是一个执行“多项目依赖”构建的工具。当你给出一些project.xml文件时,reactor会根据各项目的project.xml中所声明的依赖关系,决定它们执行的正确顺序。另外,reactor可以使用Jelly脚本在maven.xml中编写。这里我们在主项目模板的maven.xml文件中编写reactor,Foobar-Travels目录(参见图3)中的maven.xml内容如表15所示:
Listing 15 maven.xml using the reactor
表15 使用reactor的maven.xml
<project default="foobar-buildall" xmlns:m="jelly:maven">
<goal name="foobar-buildall">
<m:reactor basedir="${basedir}"
includes="*/project.xml"
goals="foobar-dist"
banner="Building"
ignoreFailures="false"/>
</goal>
</project>
The foobar-buildall goal is written as a reactor. The script for foobar-buildall in Listing 15 translates to simple English as "Starting from the base directory from where maven is executed, go to every subfolder and execute the goal identified by foobar-dist in every project.xml and stop on failure". When you go to the base directory (Foobar-Travels) and type in the command maven (since foobar-buildall is the default goal), the reactor figures out the dependency by reading all the project.xmls in the subdirectories and creates the artifacts in the required order.
这里的foobar-buildall goal中使用了reactor。表15中的foobar-buildall这段脚本翻译过来就是“从执行maven命令的根目录开始,到每个拥有project.xml文件的子目录下面执行名为‘foobar-dist’的goal,当遇到失败时,则停止” 。当你在Foobar-Travels目录下,敲入命令“maven”时(因为foobar-buildall已经被设为默认goal),reactor将会读入子目录中的所有project.xml文件,然后计算出他们的依赖关系,然后按照所需要的顺序分别生成制品。
Conclusion(结论)
This article has explained how to use Maven effectively in a J2EE project instead of plain old Ant scripts and bring about some order and modularity to the otherwise chaotic world of build and deployment. Maven is something that you should consider when looking for options to build and deploy in your project. But I've have only scratched the surface of what constitutes Maven. I hope this article has given you the confidence to build your J2EE projects with Maven and sparked your curiosity to learn more about it.
本文讲述了如何在J2EE项目中使用Maven,而不再使用简旧的Ant。使用Maven使得项目的构建部署不再混乱不堪,整个过程更加有序化、模块化。在你选择“构建项目的途径”的时候,Maven是一个相当值得考虑的方式。这里我仅讨论了Maven的浅层内容,我希望这篇文章可以给你带来在项目中使用Maven的信心,并激发你了解其更多的兴趣。
About the Author(有关作者)
Srikanth Shenoy is a Technical Architect at Objectseek Inc. (http://www.objectseek.com). He specializes in the architecture, design, development, and deployment of large J2EE and EAI projects. He has helped clients in the manufacturing, logistics, and financial sectors to realize the Java's "write once, run anywhere" dream. He is a Sun Certified Enterprise Architect and co- author of the upcoming book Practical Guide to J2EE Web Projects. You can reach him at [email protected].
Srikanth Shenoy是Objectseek( http://www.objectseek.com )公司的技术架构师。他主要专注于J2EE和EAI大项目的架构、设计、开发及部署工作。他已经帮助了许多制造业、后勤业、金融业的顾客,帮助他们实现java的“一次编写,到处执行”的梦想。他还是Sun的Certified Enterprise Architect,以及将要面世的《Practical Guide to J2EE Web Projects》的合著者。
Resources(资源)
- Download the Accompanying Source Code for this article.
- 请下载本篇文章的源代码。
Written by Srikanth Shenoy November 2003
Translated by jinfeng wang 2005年三月
原文地址:http://www.theserverside.com/articles/article.tss?l=MavenMagic
本文的翻译已经原作者同意,转载请保持原文。如有问题和意见可以和原作者或我联系。
Part 1: http://www.blogjava.net/jinfeng_wang/archive/2005/03/11/1956.html
Part 2: http://www.blogjava.net/jinfeng_wang/archive/2005/03/14/2074.html