<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>hrtc</title>
    <description></description>
    <link>http://hrtc.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>动态加载资源文件</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/221621" style="color:red;">http://hrtc.javaeye.com/blog/221621</a>&nbsp;
          发表时间: 2008年07月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>问题</h1>
<p>对于java应用中的一些配置文件每次都需要重新启动服务才能重新加载，非常麻烦，故做了一个动态加载资源的程序。</p>
<h1>可选方案</h1>
<p>使用监听线程监听文件变化，当文件变化时通知程序重新加载配置文件，用到了事件委托模型和观察者模式类似，如下</p>
<h1>公共部分</h1>
<p>&nbsp;</p>
<p>1.Listener接口</p>
<pre name="code" class="java">package com.hrtc.monitor;

/**
 * 监听器接口
 * Jul 30, 2008 3:02:28 PM
 */
public interface IMonitorListener {
	public void update(MonitorEvent event);
}
</pre>
<p>&nbsp;2.Event监听事件顶层类</p>
<pre name="code" class="java">package com.hrtc.monitor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 监听事件
 * Jul 30, 2008 3:03:12 PM
 */
public class MonitorEvent {
	private Object lock = new Object();
	private List monitorListenerList = new ArrayList();

	public void addListener(IMonitorListener listener) {
		synchronized (lock) {
			if (!monitorListenerList.contains(listener)) {
				monitorListenerList.add(listener);
			}
		}
	}

	public void removeListener(IMonitorListener listener) {
		synchronized (lock) {
			if (monitorListenerList.contains(listener)) {
				monitorListenerList.remove(listener);
			}
		}
	}

	public void removeAllListener() {
		synchronized (lock) {
			monitorListenerList.clear();
		}
	}

	/**
	 * 触发事件可由子类重载
	 */
	public void fireEvent() {
		synchronized (lock) {
			for (Iterator it = monitorListenerList.iterator(); it.hasNext();) {
				IMonitorListener listener = (IMonitorListener) it.next();
				listener.update(this);
			}
		}
	}
}
</pre>
<p>&nbsp;3.主线程监听类</p>
<pre name="code" class="java">package com.hrtc.monitor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 监听线程类
 * 
 * Jul 30, 2008 3:03:55 PM
 */
public class MonitorThread extends Thread {
	private List monitorEventList = new ArrayList();
	private long interval;
	private boolean isMonitor = false;
	private Object lock = new Object();
	private static MonitorThread monitor;

	synchronized public static MonitorThread getInstance(long intervalSecond) {
		if (monitor == null) {
			monitor = new MonitorThread(intervalSecond);
		}else{
			monitor.setInterval(intervalSecond);
		}
		return monitor;
	}

	synchronized public static MonitorThread getInstance() {
		if (monitor == null) {
			monitor = new MonitorThread(1);
		}
		return monitor;
	}

	/**
	 * 构造方法
	 * 
	 * @param intervalSecond
	 *            监听间隔时间
	 */
	public MonitorThread(long intervalSecond) {
		this.interval = intervalSecond * 1000;
	}

	public void addEvent(MonitorEvent event) {
		synchronized (lock) {
			if (!monitorEventList.contains(event)) {
				monitorEventList.add(event);
			}
		}
	}

	public void removeEvent(MonitorEvent event) {
		synchronized (lock) {
			if (monitorEventList.contains(event)) {
				monitorEventList.remove(event);
			}
		}
	}

	public void removeAllEvent() {
		synchronized (lock) {
			monitorEventList.clear();
		}
	}

	/**
	 * 监听主方法，每隔一段间隔触发事件列表
	 */
	public void run() {
		if (isMonitor) {
			return;
		}
		isMonitor = true;
		try {
			while (isMonitor) {

				synchronized (lock) {
					for (Iterator it = monitorEventList.iterator(); it
							.hasNext();) {
						MonitorEvent event = (MonitorEvent) it.next();
						event.fireEvent();
					}
				}
				Thread.sleep(interval);

			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			isMonitor = false;
		}
	}

	/**
	 * 结束监听，并不是马上结束只是把标致设为结束
	 */
	public void end() {
		isMonitor = false;
	}

	/**
	 * 是否正在监听
	 * 
	 * @return
	 */
	public boolean isMonitor() {
		return isMonitor;
	}

	public long getInterval() {
		return interval;
	}

	public void setInterval(long interval) {
		this.interval = interval;
	}

}
</pre>
<h1>&nbsp;应用案例1：可自动检查文件变化的Properties</h1>
<p>1.首先定义一个&ldquo;文件改变事件监听类&rdquo;继承自MonitorEvent</p>
<pre name="code" class="java">package com.hrtc.monitor.file;

import java.io.File;
import java.io.IOException;

import com.hrtc.monitor.MonitorEvent;

/**
 * 文件改变监听类
 * Jul 30, 2008 3:07:05 PM
 */
public class FileChangeMonitorEvent extends MonitorEvent {
	private File f;
	private long lastModifiedTime;
	private long lastLength;
	private boolean isChanged = false;

	/**
	 * 
	 * @param f 需要监听的文件
	 */
	public FileChangeMonitorEvent(File f) {
		if (!f.exists()) {
			try {
				throw new IllegalArgumentException(&quot;Path &quot;
						+ f.getCanonicalPath() + &quot; dose't exist.&quot;);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		this.f = f;
		getFileInfo();
	}

	private void getFileInfo(){
		lastModifiedTime = f.lastModified();
		lastLength = f.length();
	}
	
	/**
	 * 如果文件已改变则触发事件
	 */
	@Override
	public void fireEvent() {
		try {
			f = f.getCanonicalFile();
			isChanged = lastModifiedTime != f.lastModified() || lastLength != f.length();
			if (isChanged) {
				super.fireEvent();
				getFileInfo();
				isChanged = false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获得监听的文件
	 * @return
	 */
	public File getF() {
		return f;
	}

}
</pre>
<p>&nbsp;2.定义PropertiesEx类，以及内部类ReloadPropertiesListener</p>
<pre name="code" class="java">package com.hrtc.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import com.hrtc.monitor.IMonitorListener;
import com.hrtc.monitor.MonitorEvent;
import com.hrtc.monitor.MonitorThread;
import com.hrtc.monitor.file.FileChangeMonitorEvent;

/**
 * 可自动加载属性变化的属性类
 * Jul 30, 2008 3:10:32 PM
 */
public class PropertiesEx {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6708397622206255544L;

	private MonitorThread monitor;
	private Properties p;
	
	/**
	 * 
	 * @param intervalSecond 监听变化间隔
	 */
	public PropertiesEx(long intervalSecond) {
		monitor = MonitorThread.getInstance(intervalSecond);
	}
	
	/**
	 * 默认更新间隔为1s
	 */
	public PropertiesEx() {
		this(1);
	}

	/**
	 * 加载配置文件
	 * @param f
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public void load(File f) throws FileNotFoundException, IOException {
		p = new Properties();
		p.load(new FileInputStream(f));
		MonitorEvent event = new FileChangeMonitorEvent(f);
		ReloadPropertiesListener listener = new ReloadPropertiesListener();
		event.addListener(listener);
		monitor.addEvent(event);
		if(!monitor.isMonitor()){
			monitor.start();
		}
		
	}

	public String getProperty(String key){
		return p.getProperty(key);
	}

	public Properties getProperties(){
		return p;
	}
	
	/**
	 * 当发生属性文件改变时重新加载属性文件&lt;br&gt;
	 * listener为内部类，为了访问包含类中p成员变量和静止外部访问该类
	 * @author xuwei
	 * Jul 30, 2008 3:11:38 PM
	 */
	private class ReloadPropertiesListener implements IMonitorListener {

		public void update(MonitorEvent event) {
			FileChangeMonitorEvent fcmEvent = (FileChangeMonitorEvent) event;
			try {
				p.load(new FileInputStream(fcmEvent.getF()));
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}

	}

}
</pre>
<p>&nbsp;3.测试类</p>
<pre name="code" class="java">package com.hrtc.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import junit.framework.TestCase;

import com.hrtc.monitor.MonitorThread;

public class PropertiesExTest extends TestCase {

	protected void setUp() throws Exception {
		super.setUp();
	}

       //测试PropertiesEx中的load方法
     	public void testLoad() throws FileNotFoundException, IOException {
		System.out.println(&quot;test reload method========&quot;);
		PropertiesEx p = new PropertiesEx();
		File f = new File(PropertiesTest.class.getResource(&quot;&quot;).getPath()
				+ &quot;test.properties&quot;);
		p.load(f);
		long t1 = System.currentTimeMillis();
		int count = 10;
		int i = 0;
		try {
                       //循环10秒，在此时间内手动修改配置文件
			while (i &lt; count) {

				String name = p.getProperty(&quot;name&quot;);
				System.out.println(i + &quot;: name===&quot; + name);
				Thread.sleep(1000);

				i++;
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
	}
	
       //测试多个PropertiesEx公用同一MonitorThread
	public void testLoadMultiple() throws FileNotFoundException, IOException {
		System.out.println(&quot;test reload multiple========&quot;);
		PropertiesEx p1 = new PropertiesEx();
		File f1 = new File(PropertiesTest.class.getResource(&quot;&quot;).getPath()
				+ &quot;test.properties&quot;);
		p1.load(f1);
		PropertiesEx p2 = new PropertiesEx();
		File f2 = new File(PropertiesTest.class.getResource(&quot;&quot;).getPath()
				+ &quot;test1.properties&quot;);
		p2.load(f2);
		long t1 = System.currentTimeMillis();
		int count = 10;
		int i = 0;
		try {
			while (i &lt; count) {

				String name = p1.getProperty(&quot;name&quot;);
				String value = p2.getProperty(&quot;value&quot;);
				System.out.println(i + &quot;: &quot; + name + &quot;=&quot; + value);
				Thread.sleep(1000);

				i++;
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
               //结束监听，清除监听事件 
		MonitorThread.getInstance().end();
		MonitorThread.getInstance().removeAllEvent();
	}

}
</pre>
&nbsp;
<p>配置文件内容,与PropertiesExTest放在同一文件夹下</p>
<p>test.properties</p>
<p>&nbsp; name=name1</p>
<p>test1.properties</p>
<p>&nbsp; value=value1</p>
<p>&nbsp;</p>
<h1>总结</h1>
<p>上面的同一个MonitorThread甚至可以用到多个不同的事件中，比如除了Properties外还可以定义如xml等其他事件监听，而只用同一个MonitorThread。另一种方案是使用代理每次访问属性时查看文件是否修改，但是效率上比不上这种。</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/221621#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 30 Jul 2008 17:10:57 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/221621</link>
        <guid>http://hrtc.javaeye.com/blog/221621</guid>
      </item>
      <item>
        <title>动态加载java类</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/214510" style="color:red;">http://hrtc.javaeye.com/blog/214510</a>&nbsp;
          发表时间: 2008年07月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>目标：</h1>
<p>
当class重新编译后无需重启JVM就能加载更新过的类</p>
<h1>术语：</h1>
<p>目标类：指需要动态更新的类</p>
<h1>
对于目标类的限制：</h1>
<ul>
<li>构造函数不能有参数</li>
<li>必须实现一个接口</li>
<li>只对实例方法有效(因为接口中不能有静态方法)</li>
<li>没有考虑全局变量(可以在重新加载时复制原对象的成员，不过目前没实现)<br />
</li>
</ul>
<h1>测试代码：</h1>
<pre name="code" class="java">ClassManager manager = new ClassManager();
String className = &quot;com.hrtc.test.Test&quot;;//可换成符合上述约束的类
ITest t = (ITest) manager.getInstanceProxy(className);//当然接口也要随之变化
t.test();//test只是输出一段信息

//等待size秒，在这段时间内你必须重新编译生成你的.class文件,这里是com.hrtc.test.Test.class
int size = 5;
int i = 0;
while (i &lt; size) {
	System.out.println(i);
	i++;
	Thread.currentThread().sleep(1000);
}

t.test();//如果你修改了test输出内容则输出的内容会发生变化,此过程中没有重启jvm,也没有重新创建Test(上述代码中)

//测试动态代理和直接访问的效率，发现代理慢得多
long beginTime1 = System.currentTimeMillis();
int count = 10000;
for(int k = 0;k &lt; count;k++){
	t.test();
}
long endTime1 = System.currentTimeMillis();


ITest t2 = new Test();
long beginTime2 = System.currentTimeMillis();
for(int k = 0;k &lt; count;k++){
	t2.test();
}
long endTime2 = System.currentTimeMillis();

System.out.println(&quot;proxy time=======&quot;+(endTime1-beginTime1));
System.out.println(&quot;no proxy time=======&quot;+(endTime2-beginTime2));</pre>
<h1>
要解决的问题及解决方法</h1>
<h2>
如何重新加载类</h2>
<p>&nbsp;</p>
<p>&nbsp; 重新加载class示例代码</p>
<pre name="code" class="java">/**
 * 加载某个类
 * @param c
 * @return
 * @throws IOException
 */
@SuppressWarnings( { &quot;unchecked&quot; })
public Class loadClass(Class c) throws IOException {
	byte[] bs = loadByteCode(c);
	Class cNew = super.defineClass(c.getCanonicalName(), bs, 0, bs.length);
	return cNew;
}

/**
 * 加载某个类的字节码
 * @param c
 * @return
 * @throws IOException
 */
private byte[] loadByteCode(Class c) throws IOException {
	int iRead = 0;
	String path = c.getResource(c.getSimpleName() + &quot;.class&quot;).getPath();

	FileInputStream in = null;
	ByteArrayOutputStream buffer = null;
	try {
		in = new FileInputStream(path);
		buffer = new ByteArrayOutputStream();
		while ((iRead = in.read()) != -1) {
			buffer.write(iRead);
		}
		return buffer.toByteArray();
	} finally {
		FileUtility.safelyCloseInputStream(in);
		FileUtility.safelyCloseOutputStream(buffer);
	}
}

</pre>
<h2>&nbsp;检测类变化的方法</h2>
<p>&nbsp; 判断类创建的时间如变化则重新加载</p>
<pre name="code" class="java">/**
* 保存类路径和时间
*/
private static Map mapModify = new HashMap();

private boolean hasChanged(Class c) throws IOException {
	boolean isChanged = false;
	String path = c.getResource(c.getSimpleName() + &quot;.class&quot;).getPath();
	File f = new File(path);
	if (f.exists()) {
		Date newDate = new Date(f.lastModified());
		Date oldDate = null;
		String key = f.getCanonicalPath();
		if (mapModify.containsKey(key)) {
			oldDate = (Date) mapModify.get(key);
		} else {
			oldDate = firstDate;
		}
		isChanged = oldDate.compareTo(newDate) &lt; 0;
		if (isChanged) {
			mapModify.put(key, newDate);
		}
	}
	return isChanged;
}</pre>
<p>&nbsp;</p>
<h2>
检测类变化的时机</h2>
<h3>创建类时检查</h3>
<pre name="code" class="java">/**
 * 如果class文件重新生成过会自动加载
 * 
 * @param name
 * @return
 * @throws InstantiationException
 * @throws IllegalAccessException
 * @throws ClassNotFoundException
 * @throws IOException
 */
public Object getInstance(String name) throws InstantiationException,
		IllegalAccessException, ClassNotFoundException, IOException {
	Class c = Class.forName(name);
	Class cNew = reloadClass(c);
	if (cNew == null) {
		cNew = c;
	}
	Object o = cNew.newInstance();
	return o;
}

public synchronized Class reloadClass(Class c) throws IOException {
	Class cNew = null;
	if (hasChanged(c)) {
		cNew = loadClass(c);
	}
	return cNew;
}</pre>
<h3>&nbsp;调用方法时检查</h3>
<p>创建代理对象，自定义方法拦截器，intercept为方法拦截器中的一个方法如下</p>
<pre name="code" class="java">private Object target;

/**
 * 在调用类时判断该类是否重新编译过，如编译过则调用新类的方法
 */
public Object invoke(Object proxy, Method method, Object[] args)
		throws Throwable {
	Object targetObject = null;
	Class c = target.getClass();
	Class cNew = manager.reloadClass(c);
	if (cNew == null) {
		targetObject = target;
	} else {
		targetObject = cNew.newInstance();
		this.setTarget(targetObject);
	}
	Object returnValue = method.invoke(targetObject, args);
	return returnValue;
}


public void setTarget(Object target) {
	this.target = target;
}
</pre>
<h2>&nbsp;如何更新原来已创建的对象</h2>
<p>当class发生改变时可以更新生成新的Class类从而创建新的对象，但是原来已创建的对象怎么办呢，可以用委托实现，代码同上，此处拦截类其实是个委托类，他把方法转给target对象，并在类更新时重新定义target的引用，而从外部调用看是感觉不到这点的。</p>
<p>&nbsp;</p>
<h1>所有类代码</h1>
<pre name="code" class="java">package com.hrtc.dynamic.hot;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.proxy.Enhancer;

import com.hrtc.dynamic.proxy.DynamicProxyFactory;
import com.hrtc.test.ITest;
import com.hrtc.test.Test;

/**
 * 创建可以动态更新的java对象&lt;br&gt;
 * 限制:构造函数不能有参数
 * 必须实现一个接口
 * 只能有实例方法(因为接口中不能有静态方法)
 * @author xuwei
 * Jul 9, 2008 12:01:00 PM
 */
public class ClassManager {
	/**
	 * 保存类路径和时间
	 */
	private static Map mapModify = new HashMap();
	/**
	 * 该类被加载时的时间
	 */
	private static Date firstDate = new Date();

	/**
	 * 如果class文件重新生成过会自动加载,只有重新创建才会更新
	 * 
	 * @param name
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public Object getInstance(String name) throws InstantiationException,
			IllegalAccessException, ClassNotFoundException, IOException {
		Class c = Class.forName(name);
		Class cNew = reloadClass(c);
		if (cNew == null) {
			cNew = c;
		}
		Object o = cNew.newInstance();
		return o;
	}

	/**
	 * 创建代理对象,如果class文件重新生成过会自动加载,调用原先以实例化的方法时也会更新类
	 * 
	 * @param name
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public Object getInstanceProxy(String name) throws InstantiationException,
			IllegalAccessException, ClassNotFoundException, IOException {
		Object target = getInstance(name);

		DynamicProxyFactory factory = new DynamicProxyFactory(
				new HotInvocationHandler(this));

		return factory.newProxyInstance(target);
	}

	/**
	 * 重新加载类
	 * 
	 * @param c
	 * @return
	 * @throws IOException
	 */
	public synchronized Class reloadClass(Class c) throws IOException {
		Class cNew = null;
		if (hasChanged(c)) {
			cNew = loadClass(c);
		}
		return cNew;
	}

	private boolean hasChanged(Class c) throws IOException {
		boolean isChanged = false;
		String path = c.getResource(c.getSimpleName() + &quot;.class&quot;).getPath();
		File f = new File(path);
		if (f.exists()) {
			Date newDate = new Date(f.lastModified());
			Date oldDate = null;
			String key = f.getCanonicalPath();
			if (mapModify.containsKey(key)) {
				oldDate = (Date) mapModify.get(key);
			} else {
				oldDate = firstDate;
			}
			isChanged = oldDate.compareTo(newDate) &lt; 0;
			if (isChanged) {
				mapModify.put(key, newDate);
			}
		}
		return isChanged;
	}

	private Class loadClass(Class c) throws IOException {
		ClassLoaderAdvisor classLoader = new ClassLoaderAdvisor();
		Class cNew = classLoader.loadClass(c);
		return cNew;
	}

	public static void main(String[] args) throws IOException,
			InstantiationException, IllegalAccessException,
			ClassNotFoundException, InterruptedException {
		ClassManager manager = new ClassManager();
		String className = &quot;com.hrtc.test.Test&quot;;
		ITest t = (ITest) manager.getInstanceProxyJAVA(className);
		t.test();

		int size = 5;
		int i = 0;
		while (i &lt; size) {
			System.out.println(i);
			i++;
			Thread.currentThread().sleep(1000);
		}

		t.test();

		i = 0;
		while (i &lt; size) {
			System.out.println(i);
			i++;
			Thread.currentThread().sleep(1000);
		}

		t.test();
		
		long beginTime1 = System.currentTimeMillis();
		int count = 10000;
		for(int k = 0;k &lt; count;k++){
			t.test();
		}
		long endTime1 = System.currentTimeMillis();
		
		
		ITest t2 = new Test();
		long beginTime2 = System.currentTimeMillis();
		for(int k = 0;k &lt; count;k++){
			t2.test();
		}
		long endTime2 = System.currentTimeMillis();
		
		System.out.println(&quot;proxy time=======&quot;+(endTime1-beginTime1));
		System.out.println(&quot;no proxy time=======&quot;+(endTime2-beginTime2));
		

	}
}
</pre>
<p>&nbsp;</p>
<pre name="code" class="java">package com.hrtc.dynamic.hot;

import java.lang.reflect.Method;

import com.hrtc.dynamic.proxy.DefaultInvocationHandler;

/**
 * 拦截java方法，更新新的类
 * @author xuwei
 * Jul 9, 2008 12:02:26 PM
 */
public class HotInvocationHandler extends DefaultInvocationHandler {

	private ClassManager manager;

	public HotInvocationHandler(ClassManager manager) {
		this.manager = manager;
	}

	/**
	 * 在调用类时判断该类是否重新编译过，如编译过则调用新类的方法
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object targetObject = null;
		Class c = target.getClass();
		Class cNew = manager.reloadClass(c);
		if (cNew == null) {
			targetObject = target;
		} else {
			targetObject = cNew.newInstance();
			this.setTarget(targetObject);
		}
		Object returnValue = method.invoke(targetObject, args);
		return returnValue;
	}

}
</pre>
&nbsp;
<pre name="code" class="java">package com.hrtc.dynamic.hot;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

import com.hrtc.util.FileUtility;

public class ClassLoaderAdvisor extends ClassLoader {
	public ClassLoaderAdvisor() {
	}

	public ClassLoaderAdvisor(ClassLoader parentLoader) {
		super(parentLoader);
	}

	/**
	 * 加载某个类
	 * @param c
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings( { &quot;unchecked&quot; })
	public Class loadClass(Class c) throws IOException {
		byte[] bs = loadByteCode(c);
		Class cNew = super.defineClass(c.getCanonicalName(), bs, 0, bs.length);
		return cNew;
	}

	/**
	 * 加载某个类的字节码
	 * @param c
	 * @return
	 * @throws IOException
	 */
	private byte[] loadByteCode(Class c) throws IOException {
		int iRead = 0;
		String path = c.getResource(c.getSimpleName() + &quot;.class&quot;).getPath();

		FileInputStream in = null;
		ByteArrayOutputStream buffer = null;
		try {
			in = new FileInputStream(path);
			buffer = new ByteArrayOutputStream();
			while ((iRead = in.read()) != -1) {
				buffer.write(iRead);
			}
			return buffer.toByteArray();
		} finally {
			FileUtility.safelyCloseInputStream(in);
			FileUtility.safelyCloseOutputStream(buffer);
		}
	}
}
</pre>
&nbsp;
<pre name="code" class="java">package com.hrtc.dynamic.proxy;

import java.lang.reflect.Proxy;

/**
 * java代理工厂实现
 * @author xuwei
 * Jul 9, 2008 12:02:48 PM
 */
public class DynamicProxyFactory {
	/*
	 * 方法处理者
	 */
	private DefaultInvocationHandler invocationHandler;

	public DynamicProxyFactory() {
		this(null);
	}

	/**
	 * 
	 * @param invocationHandler
	 */
	public DynamicProxyFactory(DefaultInvocationHandler invocationHandler) {
		if (invocationHandler == null) {
			this.invocationHandler = new DefaultInvocationHandler();
		} else {
			this.invocationHandler = invocationHandler;
		}
	}

	/**
	 * 创建代理对象
	 * @param target
	 * @return
	 */
	public Object newProxyInstance(final Object target) {
		invocationHandler.setTarget(target);
		Object proxy = Proxy.newProxyInstance(target.getClass()
				.getClassLoader(), target.getClass().getInterfaces(),
				invocationHandler);
		return proxy;
	}
}
</pre>
&nbsp;
<pre name="code" class="java">package com.hrtc.dynamic.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 默认代理处理类
 * @author xuwei
 * Jul 9, 2008 12:03:00 PM
 */
public class DefaultInvocationHandler implements InvocationHandler {

	/**
	 * 目标对象
	 */
	protected Object target;

	public DefaultInvocationHandler() {
	
	}

	/**
	 * 处理方法
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println(&quot;before invoke&quot;);
		Object returnValue = method.invoke(target, args);
		System.out.println(&quot;after invoke&quot;);
		return returnValue;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}
}
</pre>
&nbsp;
<pre name="code" class="java">package com.hrtc.test;

public interface ITest {
	void test();
}
</pre>
<p>&nbsp;</p>
<pre name="code" class="java">package com.hrtc.test;

public class Test implements ITest {
	public void test() {
		System.out.println(&quot;call test method:modify here&quot;);
	}
}</pre>
<p>&nbsp;</p>
<p>目前为止上述讲到的限制没有解决，不知道有没有解决方案？</p>
<p>本文参考了http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html?page=1</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/214510#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 14 Jul 2008 11:14:05 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/214510</link>
        <guid>http://hrtc.javaeye.com/blog/214510</guid>
      </item>
      <item>
        <title>java servletfilter实现全站动转静</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/207980" style="color:red;">http://hrtc.javaeye.com/blog/207980</a>&nbsp;
          发表时间: 2008年06月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>原理及特点</h2>
<p>特点：大小仅9k，没有用额外包，jdk1.4环境开发通用性强，配置简单</p>
<p>&nbsp;</p>
<p>原理：利用filter拦截请求的jsp，如已生成静态页面且没到刷新时间则重定向静态页面，否则生成静态页面。</p>
<p>&nbsp;</p>
<p>&nbsp;* 生成策略:当前时间与上次修改时间的差值大于间隔时间则重新生成<br />
&nbsp;* 定向策略:如果是拦截的页面并以生成静态页面则重定向的静态页面<br />
&nbsp;* 静态页面文件名生成策略:源文件名+参数的md5码</p>
<h2>配置方法</h2>
<p>&nbsp;&nbsp;&nbsp; 1.引入所需包(见附件dynamictostatic_0.8.jar)</p>
<p>&nbsp;&nbsp;&nbsp; 2.web.xml里配置filter，如下</p>
<pre name="code" class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app version=&quot;2.4&quot; xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot;&gt;
	&lt;filter&gt;
		&lt;filter-name&gt;Dynamic2StaticFilter&lt;/filter-name&gt;
		&lt;filter-class&gt;com.hrtc.d2s.Dynamic2StaticFilter&lt;/filter-class&gt;

		&lt;init-param&gt;
			&lt;description&gt;刷新频率单位秒&lt;/description&gt;
			&lt;param-name&gt;refresh_time&lt;/param-name&gt;
			&lt;param-value&gt;600&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;生成静态页面线程池大小&lt;/description&gt;
			&lt;param-name&gt;threadsize&lt;/param-name&gt;
			&lt;param-value&gt;10&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;输出流缓存大小单位字节&lt;/description&gt;
			&lt;param-name&gt;buffersize&lt;/param-name&gt;
			&lt;param-value&gt;8192&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;生成的页面存放于相对于应用根路径&lt;/description&gt;
			&lt;param-name&gt;static_folder&lt;/param-name&gt;
			&lt;param-value&gt;/html&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;静态文件扩展名&lt;/description&gt;
			&lt;param-name&gt;static_extend_name&lt;/param-name&gt;
			&lt;param-value&gt;.html&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;临时文件扩展名&lt;/description&gt;
			&lt;param-name&gt;temp_extend_name&lt;/param-name&gt;
			&lt;param-value&gt;.temp&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;http head参数名&lt;/description&gt;
			&lt;param-name&gt;request_head_name&lt;/param-name&gt;
			&lt;param-value&gt;requesttype&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;init-param&gt;
			&lt;description&gt;http head参数值&lt;/description&gt;
			&lt;param-name&gt;request_head_value&lt;/param-name&gt;
			&lt;param-value&gt;download&lt;/param-value&gt;
		&lt;/init-param&gt;
	&lt;/filter&gt;

	&lt;filter-mapping&gt;
		&lt;filter-name&gt;Dynamic2StaticFilter&lt;/filter-name&gt;
		&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;
	&lt;/filter-mapping&gt;

	&lt;welcome-file-list&gt;
		&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
	&lt;/welcome-file-list&gt;
&lt;/web-app&gt;
</pre>
&nbsp;
<p>配置完毕，随便访问你网站的页面看效果吧。</p>
<p>&nbsp;</p>
<p>这是今天自己想到的方法，与大家互相学习一下，希望大家能提出改进意见。</p>
<p>&nbsp;</p>
<p>源码见附件，在windows平台上开发</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/207980#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 25 Jun 2008 18:27:06 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/207980</link>
        <guid>http://hrtc.javaeye.com/blog/207980</guid>
      </item>
      <item>
        <title>java书籍推荐</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/200166" style="color:red;">http://hrtc.javaeye.com/blog/200166</a>&nbsp;
          发表时间: 2008年06月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>基础<span style="display: none;"> L]d@D0.Z </span>
&nbsp;<br />
1.java2核心卷抽<span style="display: none;"> L\NZDkd  </span>
&nbsp;<br />
<span style="display: none;"> X5Y
`(/V </span>
  这本看完，就上手java了&nbsp;<br />
2.java语言规范<span style="display: none;"> 4q13xX </span>
&nbsp;<br />
  这本完全讲java语言规范，可谓内功心法，进国际性外企必看(指没工作经验的人)，外语加这个就ok了。<span style="display: none;"> b$O_L4CP </span>
&nbsp;<br />
<span style="display: none;"> (YHvGGr </span>
&nbsp;<br />
面向对象<span style="display: none;"> zN+*R;Ds </span>
&nbsp;<br />
1.java与模式<span style="display: none;"> .3&lt;IOtD= </span>
&nbsp;<br />
  看完这本你就正真了解了面向对象，但有可能会看不懂，看不懂是因为时机未到，别人告诉我的，不过我觉得蛮有道理的。<span style="display: none;"> `%M-7n9Y </span>
&nbsp;<br />
2.gof 设计模式<span style="display: none;"> vM7v�f6 </span>
&nbsp;<br />
  这本书被奉为经典之作，其中的原理讲的非常好，java与模式等模式类书籍都是围绕这个展开的，那为什么要看java与模式呢，因为那本容易看点，这本比较抽象，当你基本掌握了java与模式后就可以从更高的层面开始看这本书。<span style="display: none;"> 	]1d,O^S </span>
&nbsp;<br />
3.重构<span style="display: none;"> pp]_/46nN </span>
&nbsp;<br />
设计模式是最终目标，现在我们有了目标，但是仍不知道这一过程如何实现，为什么这样说呢，有些程序有一定的复杂性，不能一眼就看出用哪个模式可以解决该问
题，比如一个素数算法等等，你在写之前能看出用什么模式吗？重构是达到这一目标的手段之一，在重构过程中我们会更加接近目标。不过看这本书要有耐心。<br />
4.UML与模式应用<span style="display: none;"> P:(EU s}0 </span>
&nbsp;<br />
  学习面向对象不学uml是不行的。这本书正在看，看完再写感受。<span style="display: none;"> 3`k[!!  </span>
&nbsp;<br />
<span style="display: none;"> )ojx_3j8 </span>
&nbsp;<br />
全面认识软件工程<span style="display: none;"> -
LiPHHX&lt; </span>
&nbsp;<br />
1.人月神话<span style="display: none;">  t0e{|du </span>
&nbsp;<br />
  书老了点，但是讲的还不错。<span style="display: none;"> 1iJ0Hut}d </span>
&nbsp;<br />
2.人件<span style="display: none;"> RQ^m6)BTo </span>
&nbsp;<br />
  讲人在软件开发中的重要性，这本还没看，准备买一本。<span style="display: none;"> j9URl$T: </span>
&nbsp;<br />
3.敏捷软件开发<span style="display: none;"> 7deAr$?Wx </span>
&nbsp;<br />
  这本书讲的很全，各种思想都讲了，值得推荐。<span style="display: none;"> ]6{(Hjt </span>
&nbsp;<br />
<span style="display: none;"> =Kc|C~g </span>
&nbsp;<br />
规范篇<span style="display: none;"> 2J;kD2&quot;! </span>
&nbsp;<br />
1.servlet jsr规范<span style="display: none;"> vG�]GQ# </span>
&nbsp;<br />
  开发网页这个不得不看<span style="display: none;"> lSH	ZV
Fd </span>
&nbsp;<br />
2.http协议<span style="display: none;"> &quot;^;#f+0 </span>
&nbsp;<br />
  想真正了解服务器如何实现的推荐看下<span style="display: none;"> 9wL!D3e
{Q </span>
&nbsp;<br />
3.tcp/ip协议<span style="display: none;"> `6&amp;`wKz </span>
&nbsp;<br />
<span style="display: none;"> 8
AFMn[{ </span>
  传世经典，推荐有c基础的看下&nbsp;<br />
<span style="display: none;"> A9
U5,mOz </span>
&nbsp;<br />
高级篇<span style="display: none;"> 5XDgs|8 </span>
&nbsp;<br />
1.j2ee devleopment without ejb<span style="display: none;"> 0HqPyM13Q </span>
&nbsp;<br />
  这本书非常好，强烈推荐，最好先对ejb有了解<span style="display: none;"> 1\/{#c </span>
&nbsp;<br />
2.软件架构设计<span style="display: none;"> 
Nj+a2[ </span>
&nbsp;<br />
 对面向对象的软件架构设计讲的比较清晰，设计师必看。<span style="display: none;"> 6
jmrD� </span>
&nbsp;<br />
3.j2ee核心模式<span style="display: none;"> j	!`B'{cH </span>
&nbsp;<br />
 准备看<span style="display: none;"> GQb i$kl </span>
&nbsp;<br />
4.企业架构模式<span style="display: none;"> &quot;?35C
! </span>
&nbsp;<br />
把企业应用中的问题分析的很透彻，另外感觉hibernate中的很多思想都是出自该书。 <br />
5.分析模式<span style="display: none;"> S#tY@h@XV </span>
&nbsp;<br />
 非常好，不过比较抽象。<span style="display: none;"> z`4c	4h]I </span>
&nbsp;</p>
<p><span style="display: none;"> #AShbl	jm+ </span>
&nbsp;<br />
希望大家把看过的好书也列在下面<span style="display: none;"> KC#/Z2A|&lt;&nbsp; </span>
</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/200166#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 04 Jun 2008 17:07:15 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/200166</link>
        <guid>http://hrtc.javaeye.com/blog/200166</guid>
      </item>
      <item>
        <title>websphere5.1+spring2.0+struts2+hibernate3搭建总结</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/196721" style="color:red;">http://hrtc.javaeye.com/blog/196721</a>&nbsp;
          发表时间: 2008年05月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>最近搭建了一个websphere5.1+spring2.0+struts2+hibernate3的框架，因为jdk1.4加websphere5.1环境中间碰到一些问题，网上的解决方案也不全，今天搞了一整天总算搞定了，现与大家分享下。</p>
<p>开发工具myeclipse6，先在tomcat4 jdk4上测试，然后部署到websphere5.1上测试通过。</p>
<p>步骤：</p>
<p>1.设置编译环境为jdk1.4</p>
<p>2.把自己代码中所有1.5的特性都改成1.4</p>
<p>3.web.xml改成servlet2.3规范的</p>
<p>4.lib包不要配缺了就行</p>
<p>spring和hibernate的包都是jdk1.4编译的，不需要修改，其中cglib用的是cglib-nodep-2.1_3.jar而不是cglib-2.1_3.jar</p>
<p>struts2由于是jdk1.5编译的需要用retrotranslator转换，工具在struts2目录下的backport目录中，struts2-core-j4-2.0.11.1.jar和xwork-j4-2.0.4.jar已经转好了，再自己转个struts2-spring-plugin-j4-2.0.11.1.jar就可以了，最后把backport-util-concurrent-3.0.jar，retrotranslator-runtime-1.2.2.jar和你转好的包扔到lib目录下，原来的删除。</p>
<p>这方面网上资料还是蛮多的，不明白的可以查找下。</p>
<p>5.websphere5.1兼容性问题</p>
<p>当你成功完成上述步骤后tomcat4已经可以跑了，然后部署到websphere5.1如果没有错误的话可以运行而且后台不报错，但是页面上报XXX.action路径找不到，这个花了我好多时间才搞定，网上也没找到具体解决方案。</p>
<p>原因：</p>
<p>DefaultActionMapper类中的getUri方法：</p>
<pre name="code" class="java">String getUri(HttpServletRequest request) {
		// handle http dispatcher includes.
		String uri = (String) request
				.getAttribute(&quot;javax.servlet.include.servlet_path&quot;);
		if (uri != null) {
			return uri;
		}

		uri = RequestUtils.getServletPath(request);
		//System.out.println(&quot;url===========&quot;+uri);
		//old:if (uri != null &amp;&amp; !&quot;&quot;.equals(uri)) {
		if (uri != null &amp;&amp; uri.length() &gt; 1) {
			return uri;
		}

		uri = request.getRequestURI();
		return uri.substring(request.getContextPath().length());
	}</pre>
<p>&nbsp;发现上面注释掉的那句：</p>
<pre name="code" class="java">//System.out.println(&quot;url===========&quot;+uri);</pre>
<p>
输出为&quot;/&quot;,实际为&quot;/XX/XX.action&quot;看来是uri解析错误，猜想可能是</p>
<pre name="code" class="java">RequestUtils.getServletPath(request);</pre>
<p>
这个方法有bug，结果发现源代码没提供，所以只能在外层方法中改下了,重写了个过滤器。改完后成功运行。</p>
<p>解决方案如下，添加2个类</p>
<p>DefaultActionMapperCompaWebsphere51(修改了getUri后的判断)</p>
<pre name="code" class="java">/*
 * $Id: DefaultActionMapper.java 540141 2007-05-21 13:46:48Z mrdon $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * &quot;License&quot;); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.struts2.dispatcher.mapper;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.RequestUtils;

public class DefaultActionMapperCompaWebsphere51 extends DefaultActionMapper {
	private static ActionMapper actionMapper = new DefaultActionMapperCompaWebsphere51();
	
	public static ActionMapper getActionMapper(){
		return actionMapper;
	}
	
	/**
	 * modify uri compare
	 * @param request
	 * @return
	 */
	String getUri(HttpServletRequest request) {
		// handle http dispatcher includes.
		String uri = (String) request
				.getAttribute(&quot;javax.servlet.include.servlet_path&quot;);
		if (uri != null) {
			return uri;
		}

		uri = RequestUtils.getServletPath(request);
		//System.out.println(&quot;url===========&quot;+uri);
		//old:if (uri != null &amp;&amp; !&quot;&quot;.equals(uri)) {
		if (uri != null &amp;&amp; uri.length() &gt; 1) {
			return uri;
		}

		uri = request.getRequestURI();
		return uri.substring(request.getContextPath().length());
	}

}
</pre>
<p>&nbsp;FilterDispatcherCompaWebsphere51(调用自己刚才重写的DefaultActionMapperCompaWebsphere51)</p>
<pre name="code" class="java">/*
 * $Id: FilterDispatcherCompatWeblogic61.java 476075 2006-11-17 08:28:30Z mrdon $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * &quot;License&quot;); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.struts2.dispatcher;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.mapper.DefaultActionMapperCompaWebsphere51;

import com.opensymphony.xwork2.util.profiling.UtilTimerStack;

public class FilterDispatcherCompaWebsphere51 extends FilterDispatcher {
	private static boolean serveStatic;

	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		ServletContext servletContext = getServletContext();

		String timerKey = &quot;FilterDispatcher_doFilter: &quot;;
		try {
			UtilTimerStack.push(timerKey);
			request = prepareDispatcherAndWrapRequest(request, response);
			ActionMapping mapping;
			ActionMapper actionMapper = DefaultActionMapperCompaWebsphere51.getActionMapper();
			try {
				mapping = actionMapper.getMapping(request, dispatcher
						.getConfigurationManager());
			} catch (Exception ex) {
				log.error(&quot;error getting ActionMapping&quot;, ex);
				dispatcher.sendError(request, response, servletContext,
						HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
				return;
			}

			if (mapping == null) {
				// there is no action in this request, should we look for a
				// static resource?
				String resourcePath = RequestUtils.getServletPath(request);

				if (&quot;&quot;.equals(resourcePath) &amp;&amp; null != request.getPathInfo()) {
					resourcePath = request.getPathInfo();
				}

				if (serveStatic &amp;&amp; resourcePath.startsWith(&quot;/struts&quot;)) {
					String name = resourcePath.substring(&quot;/struts&quot;.length());
					findStaticResource(name, request, response);
				} else {
					// this is a normal request, let it pass through
					chain.doFilter(request, response);
				}
				// The framework did its job here
				return;
			}

			dispatcher
					.serviceAction(request, response, servletContext, mapping);

		} finally {
			try {
				ActionContextCleanUp.cleanUp(req);
			} finally {
				UtilTimerStack.pop(timerKey);
			}
		}
	}

	private static final Log log = LogFactory
			.getLog(FilterDispatcherCompaWebsphere51.class);

}
</pre>
<p>&nbsp;修改web.xml中原来的struts2的filter类</p>
<p>&lt;filter&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;filter-name&gt;struts2&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;filter-class&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; org.apache.struts2.dispatcher.FilterDispatcherCompaWebsphere51<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/filter-class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/filter&gt;</p>
<p>之后就可以放在tomcat和websphere5.1上运行了。</p>
<p>本文只说明了遇到的一些问题的解决方案，如何配置struts2或spring或hibernate可以参考官方资料。</p>
<p>如有不明白的可以留言。</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/196721#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 25 May 2008 16:43:37 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/196721</link>
        <guid>http://hrtc.javaeye.com/blog/196721</guid>
      </item>
      <item>
        <title>Better Builds with Maven学习笔记3</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/181422" style="color:red;">http://hrtc.javaeye.com/blog/181422</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>3.10 创建应用程序的Web站点</h2>
<p>&nbsp;&nbsp;&nbsp; 既然你已经经过了构建，测试，部署Proficio的过程，是时候让你看一下怎样为应用程序创建web站点。对于像Proficio的应用程序来说，建议在顶层目录创建源代码目录来存储资源以此生成web站点，这是默认的情况。如果你看一下，你将会发现如下的结构：<br />
&nbsp;&nbsp;&nbsp; proficio<br />
&nbsp;&nbsp;&nbsp; ----proficio-api<br />
&nbsp;&nbsp;&nbsp; ----proficio-cli<br />
&nbsp;&nbsp;&nbsp; ----proficio-core<br />
&nbsp;&nbsp;&nbsp; ----proficio-model<br />
&nbsp;&nbsp;&nbsp; ----proficio-stores<br />
&nbsp;&nbsp;&nbsp; --------proficio-store-memory<br />
&nbsp;&nbsp;&nbsp; --------proficio-store-xstream<br />
&nbsp;&nbsp;&nbsp; --------pom.xml<br />
&nbsp;&nbsp;&nbsp; ----src<br />
&nbsp;&nbsp;&nbsp; --------site<br />
&nbsp;&nbsp;&nbsp; ------------apt<br />
&nbsp;&nbsp;&nbsp; ----------------index.apt<br />
&nbsp;&nbsp;&nbsp; ------------fml<br />
&nbsp;&nbsp;&nbsp; ----------------proficio.fml<br />
&nbsp;&nbsp;&nbsp; ------------resources<br />
&nbsp;&nbsp;&nbsp; ----------------images<br />
&nbsp;&nbsp;&nbsp; --------------------flow.png<br />
&nbsp;&nbsp;&nbsp; ------------site.xml<br />
&nbsp;&nbsp;&nbsp; ----pom.xml<br />
&nbsp;&nbsp;&nbsp; 生成web站点的所有东西都在src/site目录下。在src/site目录里每一种支持的文档格式都有有一个子目录和站点描述。Maven支持许多文档格式以提供各种各样的需求。<br />
&nbsp;&nbsp;&nbsp; 目前为止，良好的支持如下：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; XDOC，一个简单的被Apache广泛使用的XML格式<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; APT(Almost Plain Text)，wiki-like格式，允许你快速输出简单的文档结构<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; FML，FAQ格式，一个简单的管理FAQs的xml格式<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 简单DocBook格式<br />
&nbsp;&nbsp;&nbsp; 限制支持：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Twiki格式，一种流行的Wiki标记格式<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 汇合(Confluence)格式，另一种流行的Wiki标记格式<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DocBook格式<br />
&nbsp;&nbsp;&nbsp; 在后面的章节我们会看一下几个支持良好的格式，但是你应该熟悉站点描述，使用如下配置<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置banner外观<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 为站点配置皮肤<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置出版日期<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置banner下的链接<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置放置在&lt;head/&gt;元素中的额外信息<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置在导航栏生成的菜单<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 配置项目报告外观<br />
&nbsp;&nbsp;&nbsp; 如果你看一下Proficio应用程序的src/site目录和其中的站点描述，你将看到如下：<br />
&nbsp;&nbsp;&nbsp; &lt;project name=&quot;Proficio&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;bannerLeft&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;href&gt;http://maven.apache.org/&lt;/href&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/bannerLeft&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;bannerRight&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;src&gt;http://maven.apache.org/images/apache-maven project.png&lt;/src&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/bannerRight&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;skin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.apache.maven.skins&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;maven-default-skin&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/skin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;publishDate format=&quot;dd MMM yyyy&quot; /&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;body&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;links&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;item name=&quot;Apache&quot; href=&quot;http://www.apache.org/&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;item name=&quot;Maven&quot; href=&quot;http://maven.apache.org/&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;item name=&quot;Continuum&quot; href=&quot;http://maven.apache.org/continuum&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/links&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;head&gt;&lt;meta name=&quot;faq&quot; content=&quot;proficio&quot;/&gt;&lt;/head&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;menu name=&quot;Quick Links&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;item name=&quot;Features&quot; href=&quot;/maven-features.html&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/menu&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;menu name=&quot;About Proficio&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;item name=&quot;What is Proficio?&quot; href=&quot;/what-is-maven.html&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/menu&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ${reports}<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/body&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 这是一个相当标准的描述，你应该知道站点描述中每个元素的意思，如下：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 站点描述&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 元素描述<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bannerLeft和bannerRight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 这个元素有一个name，href和可选的用于images的src子元素<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; skin&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 和dependency的机制相似，用来配置站点皮肤<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; publishDate&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 用SimpleDateFormat格式化日期<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; body/links&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 定义在banner下的链接，每一项有一个name和href属性<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; body/head&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 允许你在页面的head元素中插入任何东西。你可能会像加入metadata或者用来激活Google统计功能的script片段<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; body/menu&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 控制在导航栏的菜单，你可以有任意多个菜单，每个菜单可以有任意多个连接<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; body/${reports}&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 包含的${reports}引用控制是否显示站点报告。你可能会排除${reports}引用来形成一个干净的站点文档<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; Maven的一个受欢迎的特征就是可以轻易的生成标准报告。你只要简单的在你的descriptor中包括${reports}，站点报告就会自动显示。标准的项目信息报告由如下部分组成：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 依赖报告(Dependencies Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 邮件列表报告(Mailing Lists Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 连续累计报告(Continuous Integration Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 源码库报告(Source Repository Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 问题跟踪(Issue Tracking Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 项目团队报告(Project Team Report)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 许可(License)<br />
&nbsp;&nbsp;&nbsp; 虽然标准报告是有用的，但是你可能想要自定义项目报告。报告创建和展示由POM中的build/reports元素控制。你可能想要关于报告更多的选择，要这样做你需要列出每个你想包括的站点生成部分的报告，你可以像下面这样配置插件：<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;reporting&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;maven-project-info-reports-plugin&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;reportSets&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;reportSet&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;reports&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;dependencies&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;project-team&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;mailing-list&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;cim&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;!--<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Issue tracking report will be omitted<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;issue-tracking&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;license&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;report&gt;scm&lt;/report&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/reports&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/reportSet&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/reportSets&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/reporting&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 配好了配置文件以后你就可以生成站点了，命令如下：<br />
&nbsp;&nbsp;&nbsp; mvn site<br />
&nbsp;&nbsp;&nbsp; 究竟效果如何自己看一下生成的目录结构吧<br />
&nbsp;&nbsp;&nbsp; 如果你有想把pdf或图片等资源引入到你的文档中，你可以使用src/site/resources来存储他们，当站点生成时src/site/resources中的内容将被处理。src/site/resources下的任何文件或目录都会被包含在输出中，记住这个规则你可以为你的站点添加任意资源。</p>
<p>&nbsp;</p>
<p>未完待续</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/181422#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 18:55:36 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/181422</link>
        <guid>http://hrtc.javaeye.com/blog/181422</guid>
      </item>
      <item>
        <title>Better Builds with Maven学习笔记2</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/181421" style="color:red;">http://hrtc.javaeye.com/blog/181421</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>第三章 用Maven创建应用程序</h1>
<h2>3.1 介绍</h2>
<p>&nbsp;&nbsp;&nbsp; 现在你将钻研的更深一些，在这部分你将学习通过一个管理FAQ应用程序的真实例子学习Maven的最佳实践和高级应用。这个应用程序名字叫Proficio，该名字来自于拉丁语帮助的意思。</p>
<h2>3.2 建立应用程序目录结构</h2>
<p>&nbsp;&nbsp;&nbsp; Proficio的模块组成<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio API<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio的应用程序接口<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio CLI<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 提供命令行接口<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio Core<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 接口实现<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio Model<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio的数据模型<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Proficio Stores<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 存放存储模块，Proficio有一个简单的基于内存(memory-based)的仓库和一个基于流(XStream-based)的仓库<br />
&nbsp;&nbsp;&nbsp; 查看Proficio的顶层POM时，你会在modules元素下看到所有的子模块构成了Proficio应用程序。一个子模块是另一个Maven项目的引用。如下<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;packaging&gt;pom&lt;/packaging&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Maven Proficio&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;http://maven.apache.org&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modules&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-model&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-api&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-core&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-stores&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-cli&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/modules&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 上述pom中的一个特征就是版本属性为1.0-SNAPSHOT。对于一个应用程序来说，通常会一起发布许多子模块，这对于所有模块都有一个公共版本来说是很有意义的。建议你的应用程序的所有子模块都用顶层POM的版本号。<br />
&nbsp;&nbsp;&nbsp; 你应该注意packaging元素，在这个例子中它的值为pom。对于包括子模块的POMs来说，packaging类型必须被设置成pom，这告诉Maven你打算构建一个多模块的结构。目录结构如下<br />
&nbsp;&nbsp;&nbsp; proficio<br />
&nbsp;&nbsp;&nbsp; ----proficio-api<br />
&nbsp;&nbsp;&nbsp; ----proficio-cli<br />
&nbsp;&nbsp;&nbsp; ----proficio-core<br />
&nbsp;&nbsp;&nbsp; ----proficio-model<br />
&nbsp;&nbsp;&nbsp; ----proficio-stores<br />
&nbsp;&nbsp;&nbsp; --------proficio-store-memory<br />
&nbsp;&nbsp;&nbsp; --------proficio-store-xstream<br />
&nbsp;&nbsp;&nbsp; --------pom.xml<br />
&nbsp;&nbsp;&nbsp; ----pom.xml<br />
&nbsp;&nbsp;&nbsp; 各个模块的打包类型<br />
&nbsp;&nbsp;&nbsp; Module&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Packaging<br />
&nbsp;&nbsp;&nbsp; proficio-api&nbsp;&nbsp;&nbsp; jar<br />
&nbsp;&nbsp;&nbsp; proficio-cli&nbsp;&nbsp;&nbsp; jar<br />
&nbsp;&nbsp;&nbsp; proficio-core&nbsp;&nbsp;&nbsp; jar<br />
&nbsp;&nbsp;&nbsp; proficio-model&nbsp;&nbsp;&nbsp; jar<br />
&nbsp;&nbsp;&nbsp; proficio-stores&nbsp;&nbsp;&nbsp; pom<br />
&nbsp;&nbsp;&nbsp; 在大多数时候打包类型为默认的jar，但是proficio-stores这个模块类型为pom，下面是这个模块的POM<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-stores&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Maven Proficio Stores&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;packaging&gt;pom&lt;/packaging&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modules&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-store-memory&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;module&gt;proficio-store-xstream&lt;/module&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/modules&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 当你看到packaging类型为pom时，意味着该项目/模块有多个子模块构成</p>
<h2>3.3 使用项目继承</h2>
<p>&nbsp;&nbsp;&nbsp; 项目继承是Maven的一项重要特征之一。使用项目继承允许你在同一个位置声明你的组织信息，部署信息或者你的通用依赖性。你可能会注意到每个子POMs的头部会像下面这样<br />
&nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/parent&gt;<br />
&nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; 这是一个pom片段，让你利用顶层POM的资源，定义了从哪个项目继承。让我们来看一个例子。<br />
&nbsp;&nbsp;&nbsp; 如果你观察一下Proficio的顶层POM，你会发现在依赖部分有一个JUnit3.8.1的声明。在这个例子中假设Junit将被用来测试所有子项目。所以，通过继承顶层POM的依赖，在你的任何子POMs中你将不需要再次声明这个依赖。这个依赖定义如下：<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;junit&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;junit&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;3.8.1&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;scope&gt;test&lt;/scope&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 让我们来看看每个子POM发生了什么，每个子POM都继承了顶层POM的依赖部分。所以如果你看一下proficio-core模块的POM你会发现如下(注意：没有JUnit的依赖声明)<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-core&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;packaging&gt;jar&lt;/packaging&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Maven Proficio Core&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-api&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-container-default&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 为了让你看见继承的过程，你需要使用快捷工具mvn help:effective-pom命令。这个命令将让你 看到最终目标POM的结果。进入proficio-core模块目录运行上述命令，你将会看到JUnit的依赖。<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;junit&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;junit&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;3.8.1&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;scope&gt;test&lt;/scope&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 你会发现用mvn help:effective-pom命令输出的pom比预想的大很多，因为这个命令输出了合并后的整个层次结构的pom，当你遇到问题时这个命令是非常有帮助的。</p>
<h2>3.4 管理依赖</h2>
<p>&nbsp;&nbsp;&nbsp; 当你构建应用程序时，有许多依赖需要管理而且随着时间的增长依赖也不断的增长，使依赖管理变得复杂。Maven管理依赖的策略是通过把项目的继承机制和在POM中定义的依赖管理元素相结合来处理这个问题。<br />
&nbsp;&nbsp;&nbsp; 当你写的应用程序由许多独立的项目组成，很可能其中一些项目共享相同的依赖。当这个发生时，要保证所有的相同版本的依赖被你的所有项目使用，这样才能保证你的应用程序正常工作。为了在跨多个项目管理你的依赖，你使用顶层POM中的依赖管理部分来管理依赖。让我们来看一下如下部分<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencyManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-model&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-api&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-store-memory&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-store-xstream&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-core&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-container-default&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-9&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencyManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 注意：${project.version}是指顶层POM的版本元素，也就是应用程序版本<br />
&nbsp;&nbsp;&nbsp; 就像上面的依赖管理部分看到的，我们有几个Proficio依赖和一个Plexus依赖注入容器的依赖。在包括依赖元素的dependencyManagement元素和在POM顶层dependencies依赖元素有一个重要的区别：dependencyManagement只是用来定义引用的版本号，他自己不会作用于依赖层次图，而顶层dependencies元素会影响层次图。如果你观察一下proficio-api模块里的POM，你会发现依赖声明部分如下:<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-model&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 这个依赖的版本来源于顶层POM的dependencyManagement元素。只有在子项目的依赖没有声明版本时定义在祖先项目中的dependencyManagement依赖才会生效。</p>
<h2>3.5 使用快照(Snapshots)</h2>
<p>&nbsp;&nbsp;&nbsp; 当你开发拥有多个模块的应用程序时，在某些情况下每个模块更新都很频繁，需要不断的获取最新子模块(原文：it is usually the case that each of the modules are in flux)。你的APIs会改变，你的实现会改变和更新，你可能还会重构。你的构建系统需要以简单的方式来实时更新（获取最新子模块以构建项目），这就是Maven快照出现的原因。Maven中快照是用来获得最新源代码生成的产品。如果你看一下顶层Proficio的POM，你会发现快照版本定义如下:<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencyManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-model&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-api&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;${project.version}&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-container-default&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-9&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependencyManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 定义一个快照版本意味着Maven将寻找最新的依赖。快照假设依赖是被改变的，所以Maven将企图获取他们。默认情况下Maven会按日生成一次快照，但是你可以使用-U命令强迫更新。控制快照如何工作将在第七章介绍。当你定义了一个非快照的依赖，Maven将会下载依赖一次而不会再去获取他。</p>
<h2>3.6 解决依赖冲突和使用版本范围</h2>
<p>&nbsp;&nbsp;&nbsp; 当使用Maven2.0时，你只要简单的定义依赖，Maven会计算所有的依赖图。然而，当生成依赖图时，有2个或多个产品依赖不同版本号的特定依赖是不可避免的。在这种情况下依赖必须选择提供的版本。<br />
&nbsp;&nbsp;&nbsp; 在Maven中版本选择会以离版本树最近的优先选择，然而这个是有限制的：<br />
&nbsp;&nbsp;&nbsp; 1) 这个版本可能没有其他依赖所需要的特征<br />
&nbsp;&nbsp;&nbsp; 2) 如果选择了多个版本，可能会出现不确定的结果<br />
&nbsp;&nbsp;&nbsp; 要手动解决这些冲突，你可以移除版本树中不正确的版本或者你可以用正确的版本覆盖。移除不正确的版本要求识别出不正确的版本源代码，通过运行-X标记(详情见6.9)，例如：如果你在proficio-core模块中使用mvn -X test，输出将包括如下:<br />
&nbsp;&nbsp;&nbsp; proficio-core:1.0-SNAPSHOT<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; junit:3.8.1 (selected for test)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; plexus-container-default:1.0-alpha-9 (selected for compile)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; plexus-utils:1.0.4 (selected for compile)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; classworlds:1.1-alpha-2 (selected for compile)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; junit:3.8.1 (not setting scope to compile; local scope test wins)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; proficio-api:1.0-SNAPSHOT (selected for compile)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; proficio-model:1.0-SNAPSHOT (selected for compile)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; plexus-utils:1.1 (selected for compile)<br />
&nbsp;&nbsp;&nbsp; 在执行mvn -X test之前必须保证构建已经进行，所以最好先执行mvn install保证项目已经被安装到本地库中。<br />
&nbsp;&nbsp;&nbsp; 一旦版本路径已经识别出来，你可以通过在dependency中增加exclusion来排除对象图中的依赖。在上面的例子中plexus-utils出现了2次，Proficio需要1.1版本的。要保证这个，只需修改在proficio-core/pom.xml中的plexus-container-default依赖如下：<br />
&nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-container-default&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-9&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;exclusions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;exclusion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-utils&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/exclusion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/exclusions&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; 这样就保证了Maven会忽略依赖图中1.0.4版本的plexus-utils，而1.1版本的会被使用。<br />
&nbsp;&nbsp;&nbsp; 另一种保证特定版本依赖的方式是直接在POM中指定如下：<br />
&nbsp;&nbsp;&nbsp; &lt;dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-utils&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.1&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;scope&gt;runtime&lt;/scope&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/dependencies&gt;<br />
&nbsp;&nbsp;&nbsp; 然而这个方式是不建议使用的，除非你制造的产品不需要被其他程序依赖(例如:WAR包)。原因是这样做曲解了依赖图，使得难以被依赖。<br />
&nbsp;&nbsp;&nbsp; 你会注意到这里使用了runtime范围。这是因为这个例子中依赖被用在打包而不是编译。<br />
&nbsp;&nbsp;&nbsp; 上述2个方法都不是理想的，但是它能保证改进你的依赖的质量，降低构建的风险问题。如果你要发布框架的库，发布给许多人是非常重要的，这就要使用版本范围而不是指定一个特定的。<br />
&nbsp;&nbsp;&nbsp; 当版本声明为1.1就像上一个例子中的plexus-utils，这表明首选的版本是1.1，但是其他版本可能也是可接受的。Maven不知道哪些版本能运行，所以为了防止与另一个版本冲突，Maven假设所有的版本都是有效的，使用先前描述的最近依赖技术来决定选择哪个版本。用版本范围的定义方式如下：<br />
&nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.plexus&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;plexus-utils&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;[1.1,)&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br />
&nbsp;&nbsp;&nbsp; 上述的配置意味着，当使用最近依赖技术防止冲突时，其版本范围必须匹配。如果最近版本不匹配，则用第二近的，以此类推。如果都不匹配，或者没有冲突，则会使用大于1.1的版本。这时库中大于1.1的最新版本将会被使用。<br />
&nbsp;&nbsp;&nbsp; 版本范围的例子：<br />
&nbsp;&nbsp;&nbsp; Range&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Meaning<br />
&nbsp;&nbsp;&nbsp; (,1.0]&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Less than or equal to 1.0<br />
&nbsp;&nbsp;&nbsp; [1.2,1.3]&nbsp;&nbsp;&nbsp; Between 1.2 and 1.3 (inclusive)<br />
&nbsp;&nbsp;&nbsp; [1.0,2.0)&nbsp;&nbsp;&nbsp; Greater than or equal to 1.0,<br />
&nbsp;&nbsp;&nbsp; [1.5,)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Greater than or equal to 1.5<br />
&nbsp;&nbsp;&nbsp; (,1.1),(1.1,)&nbsp;&nbsp;&nbsp; Any version, except 1.1<br />
&nbsp;&nbsp;&nbsp; 使用更精确的定义可以使依赖机制更可靠和降低异常的数量。然而你不应该定义的太过精确。因为，如果2个版本范围没有交集，构建过程会失败。<br />
&nbsp;&nbsp;&nbsp; 要理解版本范围如何工作，理解版本比较是必须的。如下所示说明了版本如何分割：<br />
&nbsp;&nbsp;&nbsp; 主版本号(Major)&nbsp;&nbsp;&nbsp; 次版本号(Minor)&nbsp;&nbsp;&nbsp; 修订号(Bug fix)&nbsp;&nbsp;&nbsp; 限定符(Qualifier)&nbsp;&nbsp;&nbsp; 构建号(Build Number)<br />
&nbsp;&nbsp;&nbsp; 1.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1-&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 20060211.131141-&nbsp;&nbsp;&nbsp; 1<br />
&nbsp;&nbsp;&nbsp; 连起来就是1.0.1-20060211.131141-1<br />
&nbsp;&nbsp;&nbsp; 正如你看到的一个版本被拆分成5部分：主版本号，次版本号，修订号以及限定符和最后的构建号。对于当前的版本模式，一个快照(如前文提到的)允许有限定符和构建号。对于正规的版本，你可以只提供限定符或者只提供构建号。限定符的意图是表明一个产品在发布之前的版本(例如：alpha-1,beta-1,rc1)。对于snapshot的限定符，必须为文本&quot;snapshot&quot;或者时间戳。上例中的快照版本生成于2006-11-02 13:11:41。构建号是一个在发布后表明构建补丁的数字。<br />
&nbsp;&nbsp;&nbsp; 关于排序，这些元素被用来顺序决定哪个比较新：首先是主版本号，然后如果主版本号相同则比较次版本号，第三是修订号，第四是限定符(使用字符串比较),最后是构建号。一个带限定符的版本比不带限定符的版本旧。例如1.2-beta比1.2旧。一个带构建号的版本比不带构建号的版本新。例如：1.2-beta-1比1.2-beta新。在某些情况下版本不会匹配这个语法。在那些情况下，2个版本完全用字符串比较。<br />
&nbsp;&nbsp;&nbsp; 对于版本范围比较也一样。如果你使用的版本范围是[1.1,)，版本1.1和1.2-beta-1存在于库中，则1.2-beta-1会被选择。一般这是不希望的，为了避免这种情况，你必须组织你的发布，避免用命名规则导致上述的行为或者使用不同的库来存放你希望的版本产品。<br />
&nbsp;&nbsp;&nbsp; 无论你发布最终版本还是发布里程碑式的测试版本，你应该把它们部署到库中。这能保证测试版本只有在项目明确声明为快照时才使用范围。<br />
&nbsp;&nbsp;&nbsp; 最后一个需要注意的地方是当使用范围时如何决定版本更新。这个机制和快照一样。默认情况下，每天从库中更新一次。然而，可以配置更多的时间间隔才更新或者使用-U选项强制更新。配置间隔的例子如下：<br />
&nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;releases&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;updatePolicy&gt;interval:60&lt;/updatePolicy&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/releases&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/repository&gt;</p>
<h2>3.7 利用构建生命周期</h2>
<p>&nbsp;&nbsp;&nbsp; 在第二章里，Maven被描述成为通过良好定义的方式和过程(也就是Maven的默认构建生命周期)与可执行插件交互的框架。Maven的默认构建生命周期满足于大多数项目。但是，有些项目将有不同的需求，需要在默认生命周期基础上再增加一些阶段来满足需求。<br />
&nbsp;&nbsp;&nbsp; 例如，Proficio有一个从模型生成源代码的需求。Maven允许通过插件声明来把它绑定到默认生命周期的标准阶段&mdash;&mdash;generate-sources阶段。<br />
&nbsp;&nbsp;&nbsp; Maven中的插件根据特定的任务创建，意味着插件被绑定到默认构建生命周期。在Proficio中，Modello插件用来为数据模型生成源代码。如果你观察一下proficio-model的POM你会发现其中有一个plunins元素：<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;com.devzuz.mvnbook.proficio&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/parent&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;proficio-model&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;packaging&gt;jar&lt;/packaging&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Model&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.codehaus.modello&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;modello-maven-plugin&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-5&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;executions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;execution&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;goals&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;goal&gt;java&lt;/goal&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/goals&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/execution&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/executions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0.0&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;packageWithVersion&gt;false&lt;/packageWithVersion&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;model&gt;src/main/mdo/proficio.mdo&lt;/model&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/build&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 这个和你在第二章中看到的声明maven-compiler-plunin非常相似，但是你会看到多出了executions元素。Maven中的插件可以有多个目标，所以你需要通过指定在executions元素中的goal来定义你要运行插件中的哪个目标。</p>
<h2>3.8 使用Profiles</h2>
<p>&nbsp;&nbsp;&nbsp; Profiles让你在默认构建生命周期时创建环境变量来完成一些事情，如在不同平台构建，不同虚拟机构建，不同数据库测试或者引用本地文件系统。典型的，你试图尽可能封装POM来保证可移植的构建，但是有时你不得不考虑跨系统的环境变量，这就是Maven提供profiles的原因。<br />
&nbsp;&nbsp;&nbsp; Profiles在构建时修改POM，意味着可以为目标环境提供意义相同而定义不同的参数(例如，应用程序服务器的开发，测试，产品环境的根路径)。<br />
&nbsp;&nbsp;&nbsp; 你可以在下面三个地方定义Profiles：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1 Maven配置文件(默认：&lt;user_home&gt;/.m2/settings.xml)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2 和POM在同一文件夹下的profiles.xml文件<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 3 在POM中<br />
&nbsp;&nbsp;&nbsp; 要确定哪个profile优先，规则是就近原则。所以POM中的最高，然后是profiles.xml，最后是setting.xml。<br />
&nbsp;&nbsp;&nbsp; setting.xml可以影响到所有构建，所以他是全局的profiles。profiles.xml允许你使用一个单独的项目构建而不需要修改POM。基于POM的profiles是首选的,因为他们是可移植的(他们可以被发布到库中和可以被子构建继承使用)。<br />
&nbsp;&nbsp;&nbsp; 由于可移植性的原因，任何不能被发布到库中的文件都不能改变基本构建。因此，在profile.xml和setting.xml中定义的profiles只允许定义：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; repositories<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pluginRespositories<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; properties<br />
&nbsp;&nbsp;&nbsp; 其他的都必须定义在POM的profile中，或者POM自己或者不定义。例如，如果你有一个setting.xml需要注入一个依赖，你的项目运行时确实需要那个依赖，一旦你的工程被部署到库中，这个依赖就不能被解决，因为他的依赖设置在你的本地settings.xml而库中没有。<br />
&nbsp;&nbsp;&nbsp; 注意：repositories,pluginRespositories,properties也可以被定义在POM中。所以能在POM外面定义的profiles只是POM中可定义的profiles的一个子集。<br />
&nbsp;&nbsp;&nbsp; 你可以在POM profile中定义如下元素：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; repositories<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pluginRepositories<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dependencies<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; plugins<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; properties (not actually available in the main POM, but used behind the scenes)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; modules<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; reporting<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dependencyManagement<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; distributionManagement<br />
&nbsp;&nbsp;&nbsp; 构建元素自己可以包括如下元素：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; defaultGoal<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; resources<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; testResources<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; finalName<br />
&nbsp;&nbsp;&nbsp; 激活profiles有好几个方式：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1 -P CLI选项，后面跟以,分割的profiles-ids，例如：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; mvn -Pprofile1,profile2 install<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2 通过Maven设置中的activeProfiles部分。例如：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;settings&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profiles&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;profile1&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profiles&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activeProfiles&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activeProfile&gt;profile1&lt;/activeProfile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activeProfiles&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/settings&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 3 Profiles可以根据构建环境的检测状态自动触发。通过activation部分设定。目前这个检测被限制于前缀匹配JDK版本或者系统属性，例如：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;profile1&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;jdk&gt;1.4&lt;/jdk&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 这个活动在JDK版本为以1.4开头时触发(例如&quot;1.4.0_08&quot;,&quot;1.4.2_07&quot;,&quot;1.4&quot;)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;profile1&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;debug&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 这个将在定义了debug属性时触发<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;profile1&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;environment&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;value&gt;test&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 这个将会在定义了environment属性为test时触发<br />
&nbsp;&nbsp;&nbsp; 既然你熟悉了profiles，你打算使用他们创建定制的装配件：Proficio的装配件使用基于内存的仓库和使用基于XStream的仓库。这些装配件将在proficio-cli模块中创建，profiles用来控制这些装配件的创建。<br />
&nbsp;&nbsp;&nbsp; 下面是proficio-cli模块的profile定义：<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;!-- Profiles for the two assemblies to create for deployment --&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profiles&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;!-- Profile which creates an assembly using the memory based store --&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;memory&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;maven-assembly-plugin&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;descriptors&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;descriptor&gt;src/main/assembly/assembly-store-memory.xml&lt;/descriptor&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/descriptors&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;memory&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;!-- Profile which creates an assembly using the xstream based store --&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;xstream&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;maven-assembly-plugin&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;descriptors&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;descriptor&gt;src/main/assembly/assembly-store-xstream.xml&lt;/descriptor&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/descriptors&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/configuration&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugin&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/plugins&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;xstream&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/activation&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profile&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/profiles&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; 你可以看到2个profile：一个是基于memory的另一个是xstream。在每一个profiles中你都配置了将会创建装配件的插件描述。你将注意到使用系统属性激活profiles。你应该注意下面的例子依赖的部分应该首先被执行构建，所以应该先使用顶层项目的mvn install以保证所需的组件已经被安装到本地库。<br />
&nbsp;&nbsp;&nbsp; 如果你想创建基于内存的库，你应该执行：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; mvn -Dmemory clean assembly:assembly<br />
&nbsp;&nbsp;&nbsp; 如果你想创建基于XStream库，你应该执行：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; mvn -Dxstream clean assembly:assembly<br />
&nbsp;&nbsp;&nbsp; 上述两个装配件都被创建到目标目录，如果你在结果装配件上使用java tvf命令，你将看到基于内存的装配件只包括proficio-store-memory-1.0-SNAPSHOT.jar。这是一个非常简单的例子，但是这个例子展示了自定义生命周期profiles来适应你的需求。</p>
<h2>3.9 部署你的应用程序</h2>
<p>&nbsp;&nbsp;&nbsp; 既然你有了一个应用程序装配件，你想把它尽可能多的与人分享，所以你决定部署你的应用程序装配件。<br />
&nbsp;&nbsp;&nbsp; 现在Maven支持好几种部署方式：包括简单的file-based部署，SSH2部署,SFTP部署，FTP部署和扩展SSH部署。为了部署，你需要配置POM中的distributionManagement元素，它通常在你的顶层POM中，所以所有子POMs可以继承这些信息。下面是通过各种部署机制来配置你的POM的例子。</p>
<h3>3.9.1 以文件方式部署</h3>
<p>&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;proficio-repository&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Repository&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;file://${basedir}/target/deploy&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;</p>
<h3>3.9.2 以SSH2方式部署</h3>
<p>&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;proficio-repository&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Repository&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;scp://sshserver.yourcompany.com/deploy&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;</p>
<h3>3.9.3 以SFTP方式部署</h3>
<p>&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;proficio-repository&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Repository&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;sftp://ftpserver.yourcompany.com/deploy&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/repository&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;</p>
<h3>3.9.4 以扩展SSH方式部署</h3>
<p>&nbsp;&nbsp;&nbsp; 目前为止上述3中方式已经被Maven包含，所以只要distributionManagement就可以了，但是使用扩展SSH命令部署的话你不仅需要配置distributionManagement还需要一个build extension，如下<br />
&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;proficio-repository&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Repository&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;scpexe://sshserver.yourcompany.com/deploy&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;extensions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;extension&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.apache.maven.wagon&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;wagon-ssh-external&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-6&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/extension&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/extensions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
&nbsp;&nbsp;&nbsp; The build extension specifies the use of the Wagon external SSH provider, which does the work of moving your files to the remote server. Wagon is the general purpose transport mechanism used throughout Maven.</p>
<h3>3.9.5 以FTP方式部署</h3>
<p>&nbsp;&nbsp;&nbsp; &lt;project&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;id&gt;proficio-repository&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;name&gt;Proficio Repository&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;url&gt;ftp://ftpserver.yourcompany.com/deploy&lt;/url&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/repository&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/distributionManagement&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;extensions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;extension&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;groupId&gt;org.apache.maven.wagon&lt;/groupId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;artifactId&gt;wagon-ftp&lt;/artifactId&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;version&gt;1.0-alpha-6&lt;/version&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/extension&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/extensions&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/build&gt;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [...]<br />
&nbsp;&nbsp;&nbsp; &lt;/project&gt;<br />
一旦你配置好了相应的POM你可以执行下列命令来开始部署：mvn deploy</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>一章也显示不下，本章最后一节见下篇：http://hrtc.javaeye.com/admin/blogs/181422</p>
          <br/>
          <span style="color:red;">
            <a href="http://hrtc.javaeye.com/blog/181421#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 18:50:28 +0800</pubDate>
        <link>http://hrtc.javaeye.com/blog/181421</link>
        <guid>http://hrtc.javaeye.com/blog/181421</guid>
      </item>
      <item>
        <title>Better Builds with Maven学习笔记1</title>
        <author>hrtc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hrtc.javaeye.com">hrtc</a>&nbsp;
          链接：<a href="http://hrtc.javaeye.com/blog/178975" style="color:red;">http://hrtc.javaeye.com/blog/178975</a>&nbsp;
          发表时间: 2008年04月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>主要是翻译一下Better Builds with Maven这本书，尽量精简，做个笔记而已，初学maven有不对的地方请指正。所以也不敢说有什么体会，看一章写一章。</p>
<h1>第一章 Maven介绍</h1>
<h2>Maven是什么</h2>
<p>&nbsp;&nbsp;&nbsp; Maven包括一系列构建标准：一个产品库模型，一个管理和描述项目的软件引擎。定义了构建、测试、部署项目产品的标准生命周期。提供了一个简单实用符合Maven标准的通用构建逻辑。是一个在Apache软件基金会下的开源项目，是一个声明式项目管理工具(通过项目对象模型Project Object Model）,用来简化软件项目管理过程的框架。</p>
<h2>Maven好处</h2>
<h3>一致(Coherence)</h3>
<p>&nbsp;&nbsp;&nbsp; Maven以一系列最佳实践为基础使组织标准化，因为Maven是根据标准化模型构造的。</p>
<h3>重用(Reusablity)</h3>
<p>&nbsp;&nbsp;&nbsp; Maven构建于可重用的基础之上。当你使用Maven时你可以高效的重用整个行业完整的最佳实践。</p>
<h3>敏捷(Agility)</h3>
<p>&nbsp;&nbsp;&nbsp; Maven降低了重用构建逻辑和软件组件的门槛。使创建一个组件然后再整合它到多个项目中变得容易。</p>
<h3>可维护(Maintainability)</h3>
<p>&nbsp;&nbsp;&nbsp; 使用Maven的组织不必为了构建而构建，可以集中精力于构造应用程序。Maven项目的可维护性是很高的，因为它遵从了通用的公共定义模型。</p>
<h2>Maven原则</h2>
<h3>习惯优于配置(Convention over configuration)</h3>
<h4>&nbsp;&nbsp;&nbsp; 标准的项目目录结构</h4>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 这个就不解释了，应该都明白</p>
<h4>&nbsp;&nbsp;&nbsp; 一个项目一个主输出的思想</h4>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 举个例子，如果有一个客户端/服务端项