<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Java论坛最新讨论 - JavaEye</title>
    <description>Java编程、Java Web开发、Java企业应用、Java设计模式、Java开源框架、Java应用服务器 <br/>
圈子: 
<a href="http://android.group.javaeye.com/" target="_blank">Android</a>
<a href="http://jbpm.group.javaeye.com/" target="_blank">JBPM</a>
<a href="http://jsfgroup.group.javaeye.com/" target="_blank">JSF</a>
<a href="http://seam.group.javaeye.com/" target="_blank">Seam</a>
<a href="http://tapestrying.group.javaeye.com/" target="_blank">Tapestry</a>
<a href="http://grails.group.javaeye.com" target="_blank">Groovy</a>
<a href="http://lucene-group.group.javaeye.com/" target="_blank">Lucene</a>
<a href="http://ecside.group.javaeye.com/" target="_blank">GT-Grid</a>

 - Java编程，Ruby编程，微软.net，AJAX，敏捷软件开发，综合软件技术</description>
    <link>http://www.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>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://frh0792.javaeye.com">frh0792</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234835" style="color:red;">http://www.javaeye.com/topic/234835</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          我想知道一些常用的过滤器，比如中文过滤（这个我会），还有过滤地址的，防止sql注入脚本的（这类形式：‘ or ‘’=’），总之，越多越好，项目的安全第一嘛，小弟感激不尽。
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234835" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 19:03:33 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234835</link>
        <guid>http://www.javaeye.com/topic/234835</guid>
      </item>
      <item>
        <title>自己写的一些web常用的类库</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://key232323.javaeye.com">key232323</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234582" style="color:red;">http://www.javaeye.com/topic/234582</a>&nbsp;
          发表时间: 2008年08月29日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>附有源码。</p>
<p>对快速小型web应用很有效。</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234582" style="color:red;">已有 <strong>1</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Fri, 29 Aug 2008 19:15:37 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234582</link>
        <guid>http://www.javaeye.com/topic/234582</guid>
      </item>
      <item>
        <title>Weblogic是不是快要SQQ了？</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://polygoncell.javaeye.com">polygoncell</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234594" style="color:red;">http://www.javaeye.com/topic/234594</a>&nbsp;
          发表时间: 2008年08月29日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          先表明身份，我是JBoss用户，项目中使用EJB3，对于使用其他的Application Server并不排斥。<br /><br />今天无聊，上Amazon看看有什么新书，心血来潮，找了找关于三大AS的书，结果发现关于Weblogic的书基本上从2004开始就再也没有出过新的。唯独有一本2007年出的书:Affinity: Managing Java Application Servers涉及到weblogic，但是并不是单独针对weblogic的。<br /><br />看看websphere，06，07，08都一直有新书在出版。<br /><br />关于JBoss的书在06， 07年也沉寂了好长一段时间，不过JBoss本身的开发进度也不是很快，AS 5 RC1才发布了2个多月。 我目前一直在用4.2.x，盼星星盼月亮地盼着JBoss AS 5 GA发布，到现在还是未知数。 说道书，最新的JBoss in Action已经基本完稿，发布在即，必入。<br /><br />哦对了，还有个新秀Glassfish，目前还是初期阶段，amazon上有两本相关书籍，未来情况不明，观望。 <br />至于Geronimo，目前还没听说哪位朋友在项目中真正采用的，Amazon上有两本相关书籍，均是2006年出版的，观望。<br /><br />个人认为，使用JBoss的人看重它开源，有活跃的社区，有丰富的书籍和文档，开发过程中出现问题话，有足够多的途径来解决：或者看书看文档，或者到社区提问，再不济也可以读代码。<br /><br />单从相关技术书籍出版现状来看，Weblogic似乎快不行了，至少已经淡出了技术书籍作者的视线。<br /><br />我没有使用过weblogic，所以不太清楚大家是怎么开发的，从哪里获得必要的开发资源的，oracle提供的技术支持作用大么？大家在项目中使用weblogica的多么？
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234594" style="color:red;">已有 <strong>4</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Fri, 29 Aug 2008 20:18:57 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234594</link>
        <guid>http://www.javaeye.com/topic/234594</guid>
      </item>
      <item>
        <title>实现自己的拦截器框架</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chenyinghua.javaeye.com">iwindyforest</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234814" style="color:red;">http://www.javaeye.com/topic/234814</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          AOP技术是spring框架的一个重要特征。通过该特性能够在<strong>函数运行之前，之后，或者异常处理的时候</strong>执行我们需要的一些操作。<br /><br />下面我们就是需要抛开AOP，Spring这样成型的框架不用，而仅仅使用java反射机制中的Proxy,InvocationHandler来实现类似Spring框架的拦截器的效果。<br /><br /><strong><span style="font-size: xx-large">动态代理DynamicProxy</span></strong><br /><br />首先，在设计这个拦截器框架之前，我们需要明白java中动态代理是什么？我想如果早就清楚请直接跳过，如果需要了解，那我想你手边最好有一个javadoc的电子书。<br /><br />Java.lang.reflect.Proxy是反射包的成员之一。具体说明请查javadoc。<br />用法就是比如有一个对象，我们需要在调用<strong>它提供的方法</strong>之前，干点别的什么，就不能直接调用它，而是生成一个它的代理，这个代理有<strong>这个对象所提供的所有接口方法</strong>，我们通过直接调用代理的这些方法，来实现：<strong>函数既能像原来对象的那样工作，又能在函数运行过程前后加入我们自己的处理。</strong><br /><br />这个类有个非常重要的函数用来实现某个类的代理：<br /><pre name="code" class="java">
Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, 
             Class&lt;?>[] interfaces, 
             InvocationHandler h) throws IllegalArgumentException
</pre><br /><br />参数有点迷惑人，解释下：<br /><strong>ClassLoader</strong> 是类加载器，这个参数用来定义代理类，一般使用原对象的即可，也可以为null用上下文解决。<br /><strong>Class&lt;?>[]</strong> 接口数组,就是我们需要这个代理能够提供原来的类的什么函数。如果全部则直接<strong>class.getInterfaces()</strong>来解决.<br /><strong>InvocationHandler</strong> 调用处理器，这个就是如果你调用代理的方法，那么这个处理器就会被关联过来，处理调用这个函数的整个过程。这个接口只定义了一个方法：<br /><pre name="code" class="java">
public Object invoke(Object proxy, Method method, 
                  Object[] args) throws Throwable;
</pre><br />参数中<strong>proxy</strong>就是你调用的代理，<strong>method</strong>指的是你调用的代理的那个方法，<strong>args</strong>是传给该方法的参数。<br /><br />我们生成某个类的代理步骤，一般需要先考虑我们在调用这个类的函数的时候（之前，或者之后）如何处理某些事情，因此我们首先考虑的就是如何实现<strong>InvocationHandler</strong>这个接口。<br /><br />让我们做一个实践，做这么一个调用处理器：任何使用此处理器的代理在调用它的任何方法的时候，都打印<strong>被代理的类的类名+“.”+方法名+”(“+参数+”,”+参数+...+”)”</strong>。<br /><br />步骤1: 定义接口<strong>IUser</strong><br /><pre name="code" class="java">
package com.cyh.proxy.sample;

public interface IUser {
    public String getName();

    public void setName(String name);
}
</pre><br /><br />步骤2: 写IUser接口的实现类<strong>User</strong><br /><pre name="code" class="java">
package com.cyh.proxy.sample.impl;

import com.cyh.proxy.sample.IUser;

public class User implements IUser {
    String name;

    public User(String name) {
	this.name = name;
    }

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }
}
</pre><br /><br />步骤3: 写<strong>TraceHandler</strong>实现调用处理器<strong>InvocationHandler</strong>,即在<strong>invoke()</strong>方法里我们要打印被<strong>代理的类的类名+“.”+方法名+”(“+参数+”,”+参数+...+”)”</strong>。<br /><br /><pre name="code" class="java">
package com.cyh.proxy.sample.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TraceHandler implements InvocationHandler {
    private Object target;

    public TraceHandler(Object target) {
	this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
	    throws Throwable {

	// print implicit argument
	System.out.print(target.getClass().getName());
	// print method name
	System.out.print("." + method.getName() + "(");
	// print explicit arguments
	if (args != null) {
	    for (int i = 0; i &lt; args.length; i++) {
		System.out.print(args[i]);
		if (i &lt; args.length - 1) {
		    System.out.print(",");
		}
	    }
	}
	System.out.println(")");

	return method.invoke(this.target, args);
    }
}
</pre><br /><br />步骤4: 最后,让我们写测试类<strong>ProxyTest</strong><br /><pre name="code" class="java">
package com.cyh.proxy.sample.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.cyh.proxy.sample.IUser;
import com.cyh.proxy.sample.impl.TraceHandler;
import com.cyh.proxy.sample.impl.User;

public class ProxyTest {
    User user;

    public ProxyTest() {
	user = new User("LaraCroft");

	ClassLoader classLoader = user.getClass().getClassLoader();
	Class[] interfaces = user.getClass().getInterfaces();
	InvocationHandler handler = new TraceHandler(user);
	IUser proxy = (User) Proxy.newProxyInstance(classLoader, interfaces,
		handler);

	proxy.setName("David Beckham");
    }

    public static void main(String[] args) {
	new ProxyTest();
    }

}
</pre><br /><br /><br />好了,所有代码写好了,运行一下,测试结果是:<br /><strong>com.cyh.proxy.impl.User.setName(David Beckham)</strong><br /><br />讲一下运行原理：<br />首先我们初始化了user对象，user.name = = “LaraCroft”;<br />然后创建了user对象的代理proxy。<br />注意这里：<strong>Proxy.newProxyInstance()函数的返回值使用接口IUser转型的，你或许会想到<br />用User来做强制类型转换，但是会抛出下面的异常</strong><br /><span style="color: red">Exception in thread "main" java.lang.ClassCastException: $Proxy0 cannot be cast to com.cyh.proxy.impl.User</span> <br /><strong>因为：代理类是实现了User类的所有接口，但是它的类型是$Proxy0，不是User。</strong><br /><br />最后，我们调用代理的setName()方法：<br /><strong>proxy.setName("David Beckham");</strong><br /><br />代理在执行此方法的时候，就好触发调用处理器 TraceHandler，并执行 TraceHandler的invoke()方法，然后就会打印：<br /><strong>com.cyh.proxy.impl.User.setName(David Beckham)</strong><br /><br /><br /><br /><span style="font-size: xx-large"><strong>拦截器框架的实现</strong></span><br /><br /><br />好了，关于代理的知识我们讲完了，我们可以考虑如何实现这个拦截器的框架，所谓<strong>拦截器就是在函数的运行前后定制自己的处理行为</strong>，也就是通过实现<strong>InvocationHandler</strong>达到的。<br /><br /><br /><span style="font-size: x-large"><strong>设计思路</strong></span><br /><br /><br />我们来理清一下思路，在使用一个拦截器的时候？<strong>什么是不变的，什么是变化的？</strong><br /><br /><strong>不变的：</strong><br />每次都要创建代理<br />拦截的时间：函数执行之前，之后，异常处理的时候<br /><br /><strong>变化的：</strong><br />每次代理的对象不同<br />拦截器每次拦截到执行时的操作不同<br /><br />好了，废话少说，看类图：<br /><br /><img src="http://www.javaeye.com/upload/attachment/36855/1ff800fd-12d0-36b8-b606-6f6b6255fcb4.png" /><br /><br />图中：<br /><strong>DynamicProxyFactory</strong> 和它的实现类，是一个工厂，用来创建代理<br /><br /><strong>Interceptor</strong> 这个接口用来定义拦截器的拦截处理行为配合DynamicProxyInvocationHandler达到拦截效果<br /><strong>DynamicProxyInvocationHandler</strong> 调用处理器的实现，它有两个成员，一个是Object target指的是被代理的类，另一个是Interceptor interceptor就是在invoke()方法执行target的函数之前后，异常处理时，调用interceptor的实现来达到拦截，并处理的效果。<br /><br /><br /><span style="font-size: x-large"><strong>代码实现</strong></span><br /><br />步骤1: 定义接口<strong>DynamicProxyFactory</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor;

public interface DynamicProxyFactory {
    /**
     * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
     * 
     * @param clazz
     *            需要实现的接口
     * @param target
     *            实现此接口的类
     * @param interceptor
     *            拦截器
     * @return
     */
    public &lt;T> T createProxy(T target, Interceptor interceptor);
}
</pre><br /><br />步骤2: 定义接口<strong>Interceptor</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor;

import java.lang.reflect.Method;

public interface Interceptor {
    public void before(Method method, Object[] args);

    public void after(Method method, Object[] args);

    public void afterThrowing(Method method, Object[] args, Throwable throwable);

    public void afterFinally(Method method, Object[] args);
}
</pre><br /><br />步骤3: 实现接口<strong>DynamicProxyFactory</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.cyh.proxy.interceptor.DynamicProxyFactory;
import com.cyh.proxy.interceptor.Interceptor;

public class DynamicProxyFactoryImpl implements DynamicProxyFactory {
    /**
     * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
     * 
     * @param target
     *  需要代理的实例
     * @param interceptor
     *  拦截器实现,就是我们希望代理类执行函数的前后,
     *  抛出异常,finally的时候去做写什么
     */
    @Override
    @SuppressWarnings("unchecked")
    public &lt;T> T createProxy(T target, Interceptor interceptor) {
	// 当前对象的类加载器
	ClassLoader classLoader = target.getClass().getClassLoader();
	// 获取此对象实现的所有接口
	Class&lt;?>[] interfaces = target.getClass().getInterfaces();
	// 利用DynamicProxyInvocationHandler类来实现InvocationHandler
	InvocationHandler handler = new DynamicProxyInvocationHandler(target,
		interceptor);

	return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}
</pre><br /><br />步骤4: 实现调用处理器<br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.cyh.proxy.interceptor.Interceptor;

/**
 * 动态代理的调用处理器
 * 
 * @author chen.yinghua
 */
public class DynamicProxyInvocationHandler implements InvocationHandler {
    private Object target;
    private Interceptor interceptor;

    /**
     * @param target
     *            需要代理的实例
     * @param interceptor
     *            拦截器
     */
    public DynamicProxyInvocationHandler(Object target,
                                  Interceptor interceptor) {
	this.target = target;
	this.interceptor = interceptor;
    }

    /**
     * @param proxy
     *            所生成的代理对象
     * @param method
     *            调用的方法示例
     * @args args 参数数组
     * @Override
     */
    public Object invoke(Object proxy, Method method, Object[] args)
	    throws Throwable {
	Object result = null;

	try {
	    // 在执行method之前调用interceptor去做什么事
	    this.interceptor.before(method, args);
	    // 在这里我们调用原始实例的method
	    result = method.invoke(this.target, args);
	    // 在执行method之后调用interceptor去做什么事
	    this.interceptor.after(method, args);
	} catch (Throwable throwable) {
	    // 在发生异常之后调用interceptor去做什么事
	    this.interceptor.afterThrowing(method, args, throwable);
	    throw throwable;
	} finally {
	    // 在finally之后调用interceptor去做什么事
	    interceptor.afterFinally(method, args);
	}

	return result;
    }

}
</pre><br /> <br />好了，目前为止，这个框架算完成了，怎么用呢？<br />接下来我们完成测试包。<br /><br /><span style="font-size: x-large"><strong>完成测试</strong></span><br /><br />步骤1： 首先，给需要代理的类定义一个接口<strong>Service</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.test;

public interface Service {
    public String greet(String name);
}
</pre><br />步骤2： 实现这个接口，编写类<strong>ServiceImpl</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.test;

public class ServiceImpl implements Service {
    @Override
    public String greet(String name) {
	String result = "Hello, " + name;
	System.out.println(result);
	return result;
    }
}
</pre><br />步骤3： 实现拦截器接口Interceptor，编写类<strong>InterceptorImpl</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.test;

import java.lang.reflect.Method;

import com.cyh.proxy.interceptor.Interceptor;

public class InterceptorImpl implements Interceptor {
    @Override
    public void after(Method method, Object[] args) {
	System.out.println("after invoking method: " + method.getName());
    }

    @Override
    public void afterFinally(Method method, Object[] args) {
	System.out.println("afterFinally invoking method: " + method.getName());
    }

    @Override
    public void afterThrowing(Method method, Object[] args, 
                                Throwable throwable) {
	System.out.println("afterThrowing invoking method: "
                                                + method.getName());
    }

    @Override
    public void before(Method method, Object[] args) {
	System.out.println("before invoking method: " + method.getName());
    }
}
</pre><br />步骤4：编写测试类<strong>TestDynamicProxy</strong><br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.test;

import com.cyh.proxy.interceptor.DynamicProxyFactory;
import com.cyh.proxy.interceptor.Interceptor;
import com.cyh.proxy.interceptor.impl.DynamicProxyFactoryImpl;

public class TestDynamicProxy {
    public TestDynamicProxy() {
	DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactoryImpl();
	Interceptor interceptor = new InterceptorImpl();
	Service service = new ServiceImpl();

	Service proxy = dynamicProxyFactory.createProxy(service, interceptor);
	// Service proxy = DefaultProxyFactory.createProxy(service,
	// interceptor);
	proxy.greet("iwindyforest");
    }

    public static void main(String[] args) {
	new TestDynamicProxy();
    }
}
</pre><br /><br />好了，整个测试包完成了，让我们运行下看看运行结果：<br /><strong><br />before invoking method: greet<br />Hello, iwindyforest<br />after invoking method: greet<br />afterFinally invoking method: greet<br /></strong><br /><br /><br /><span style="font-size: x-large"><strong>完善设计</strong></span><br /><br />现在，让我们回顾一下：接口<strong>DynamicProxyFactory</strong>，真的需要么？<br />它只是一个工厂，负责生产代理的，但是我们并没有过多的要求，因此可以说它的实现基本上是不变的。鉴于此，我们在使用<strong>createProxy()</strong>函数的时候，只需要一个<strong>静态方法</strong>就可以了，没有必要再初始化整个类，这样才比较方便么。<br />因此，我在<strong>com.cyh.proxy.interceptor.impl</strong>包里加了一个默认的工厂<strong>DefaultProxyFactory</strong>：<br /><pre name="code" class="java">
package com.cyh.proxy.interceptor.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.cyh.proxy.interceptor.Interceptor;

public class DefaultProxyFactory {
    @SuppressWarnings("unchecked")
    public static &lt;T> T createProxy(T target, Interceptor interceptor) {
	// 当前对象的类加载器
	ClassLoader classLoader = target.getClass().getClassLoader();
	// 获取此对象实现的所有接口
	Class&lt;?>[] interfaces = target.getClass().getInterfaces();
	// 利用DynamicProxyInvocationHandler类来实现InvocationHandler
	InvocationHandler handler = new DynamicProxyInvocationHandler(target,
		interceptor);

	return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}
</pre><br /><br /><span style="font-size: x-large"><strong>参考书籍：</strong></span><br /><br /><span style="color: red"><br />Core java Volume I<br />深入浅出JDK6.0<br /></span><br /><br /><span style="color: blue"><br />P.S：本来想系统的写一下反射的学习笔记来，刚刚写了个开头，回来在看，发现写的东西真是很基本很基本，心想这样的东西放到java区没准就会被打到“新手区”了，因此还是没有写，不过临发这篇文章，我心里还是比较忐忑：又是一篇写轮子的文章，这次会不会又进新手区了？<br /></span>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234814" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 17:06:09 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234814</link>
        <guid>http://www.javaeye.com/topic/234814</guid>
      </item>
      <item>
        <title>另类加水印——根据明暗度分别加不同的水印</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jsnjlc.javaeye.com">jsnjlc</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234671" style="color:red;">http://www.javaeye.com/topic/234671</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          公司里要求上传的照片都要加上公司的logo,统一打在又下角。但是,由于照片有暗有亮，因此logo分成了2种，1种是在比较亮的情况下打的，1种是在比较暗的情况下打的。这可把我害惨了，如何判断明暗度嘛。奋力Google了1天终于理解，于是写出了实现代码。<br />由于注释写的比较全，因此不再进行解释，里面也有测试方法，可以进行下测试。<br /><br /><br /><span style="color: red"><strong>PS:目标图请做好备份,因为其会直接覆盖目标图</strong></span><br /><pre name="code" class="java">
package image;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.FileOutputStream;

import javax.imageio.ImageIO;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class WaterMark {

    /**
     * 获取指定矩形中的像素的矩阵
     * 
     * @param imageSrc
     * @param startX
     * @param startY
     * @param w
     * @param h
     * @return
     */
    private int[] getPixArray(Image imageSrc, int startX, int startY,
            int w, int h) {
        int[] pix = new int[(w - startX) * (h - startY)];
        
        /*下面是别人程序中的一段,我实在不明白为何要加这一段,因为我去掉也没有问题,加上还会报错*/
        PixelGrabber pg = null;
        try {
            pg = new PixelGrabber(imageSrc, startX, startY, w-startX, h-startY, pix, 0, w);
            if (pg.grabPixels() != true) {
                try {
                    throw new java.awt.AWTException("pg error" + pg.status());
                } catch (Exception eq) {
                    eq.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return pix;
    }

    /**
     * 将1张图片和另1张图片的指定区域重合。可用于制作水印。图片的左上角坐标为0，0
     * 
     * @param lightnessWaterImg
     *            颜色比较亮的水印图片，适合底色比较暗的情况
     * @param darknessWaterImg
     *            颜色比较暗的水印图片，适合底色比较亮的情况,如果不想区分，则输入null，平均灰度边界同时失效。
     * @param targetImg
     *            源图片
     * @param startX
     * @param startY
     * @param x
     * @param y
     * @param alpha
     *            透明度,0f为全透明,1f为完全不透明,0.5f为半透明
     * @param averageGray
     *            平均灰度边界（0-255），大于此值，则打暗的水印图片，小于此值则打亮的水印图片。
     *            默认值128。超过范围，按默认值进行。
     */
    private final void pressImage(String lightnessWaterImg,
            String darknessWaterImg, String targetImg, int startX, int startY,
            int x, int y, float alpha, float averageGray) {
        try {
            // 先判断亮水印和源文件的值是否为null，否则抛出异常
            if (lightnessWaterImg == null || lightnessWaterImg == ""
                    || targetImg == null || targetImg == "") {
                throw new Exception("亮水印或者源图片的地址不能为空");
            } 
            // 再判断平均灰度边界是否越界
            if (averageGray>255||averageGray&lt;0) {
                averageGray = 128;
            }
            

            // 装载源图片
            File _file = new File(targetImg);
            // 图片装入内存
            BufferedImage src = ImageIO.read(_file);
            // 获取图片的尺寸
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            // 根据源图片尺寸，设置预装载的一个图片，默认是RGB格式的
            BufferedImage image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = image.createGraphics();
            // 绘制内存中的源图片至指定的矩形内
            graphics.drawImage(src, 0, 0, width, height, null);
            // 在已经绘制的图片中加入透明度通道
            graphics.setComposite(AlphaComposite.getInstance(
                    AlphaComposite.SRC_ATOP, alpha));
            

            // 获取源图片中和设定的同样大小的区域内的像素集合
            int[] pixels = getPixArray(src, startX, startY, x, y);

            //查询此集合的平均灰度
            float average = getAverageGrap(x-startX,y-startY,pixels);

            // 如果平均灰度大于130,则说明此区域比较亮，否则则比较暗
            System.out.println(average);

            
            //装载水印图片所需参数
            File water;
            BufferedImage bufferwater;
            
            // 根据设定的平均灰度边界来装载不同的水印
            if (darknessWaterImg == null||average>=averageGray) {
                // 装载亮水印文件
                water = new File(darknessWaterImg);
            }else{
                // 装载暗水印文件
                water = new File(lightnessWaterImg);
            }
            // 装入内存
            bufferwater = ImageIO.read(water);
                        
            graphics.drawImage(bufferwater, startX, startY, x, y,
                    null);
            // 水印文件结束
            graphics.dispose();
            FileOutputStream out = new FileOutputStream(targetImg);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            // 绘制新的文件
            encoder.encode(image);
            out.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        
    /**
     * 查询某个区域的平均灰度
     * @param width
     * @param height
     * @param pixels
     * @return
     */
    private float getAverageGrap(int width,int height,int[] pixels){
        /* 下面是开始算这个区域的亮度了，灰度等同于亮度 */
        ColorModel colorModel = ColorModel.getRGBdefault();
        int i = 0;
        int j = 0;
        int k = 0;
        int r = 0;
        int g = 0;
        int b = 0;
        int gray = 0;
        float average = 0;// 平均灰度
        for (i = 0; i &lt; height; i++) {
            for (j = 0; j &lt; width; j++) {
                // 定位像素点
                k = i * width + j;
                r = colorModel.getRed(pixels[k]);
                g = colorModel.getGreen(pixels[k]);
                b = colorModel.getBlue(pixels[k]);

                // 计算灰度值
                gray = (r * 38 + g * 75 + b * 15) >> 7;

                average = average + gray;
            }
        }
        // 计算平均灰度
        average = average / ((i - 1) * (j - 1));
        return average;
    }
    public static void main(String[] args) {
        WaterMark waterMark = new WaterMark();

        waterMark.pressImage("F:\\Mine\\My Pictures\\素材\\w2.png", "F:\\Mine\\My Pictures\\素材\\w1.png",
                "F:\\Mine\\My Pictures\\素材\\2.jpg", 520, 500, 900, 800, 0.5f, 50);
        System.out.print("添加成功");
    }

}
</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234671" style="color:red;">已有 <strong>1</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 01:06:24 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234671</link>
        <guid>http://www.javaeye.com/topic/234671</guid>
      </item>
      <item>
        <title>extremecomponents 怎么配置</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://zhuowenxiong.javaeye.com">zhuowenxiong</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234795" style="color:red;">http://www.javaeye.com/topic/234795</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          请问有那个知道extremecomponents 在jbuilder里的配置
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234795" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 15:12:49 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234795</link>
        <guid>http://www.javaeye.com/topic/234795</guid>
      </item>
      <item>
        <title>为什么OpenEntityManagerInViewFilter无法提交事务，也就是不能保存实体</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hypercube1024.javaeye.com">hypercube1024</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234792" style="color:red;">http://www.javaeye.com/topic/234792</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          我用的Ext2 + DWR + Spring MVC + Spring + JPA这样的框架开发，配置了OpenEntityManagerInViewFilter代码如下:<br /><pre name="code" class="xml">
&lt;filter>
  &lt;filter-name>jpaFilter&lt;/filter-name>
  &lt;filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter&lt;/filter-class>
&lt;/filter>
&lt;filter-mapping>
  &lt;filter-name>jpaFilter&lt;/filter-name>
  &lt;url-pattern>/*&lt;/url-pattern>
&lt;/filter-mapping> 
</pre> <br />在Java类里面的main函数测试了一userService.save(user)下可以保存实体，但是从web页面Ext提交过来的表单就保存不了，就好像没有提交事务那种情况一样，但是通过log发现userService.save()方法肯定是执行了的。<br />applactionContext.xml配置如下:<br /><pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
<a href="http://www.springframework.org/schema/beans" target="_blank">http://www.springframework.org/schema/beans</a> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
<a href="http://www.springframework.org/schema/context" target="_blank">http://www.springframework.org/schema/context</a> http://www.springframework.org/schema/context/spring-context-2.5.xsd
<a href="http://www.springframework.org/schema/jee" target="_blank">http://www.springframework.org/schema/jee</a> http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
<a href="http://www.springframework.org/schema/tx" target="_blank">http://www.springframework.org/schema/tx</a> http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    
    &lt;context:annotation-config />
    &lt;context:component-scan base-package="com.xxx.xxx" />
    &lt;bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
   	&lt;bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        &lt;property name="dataSource" ref="dataSource" />
        &lt;property name="jpaVendorAdapter">
            &lt;bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                &lt;property name="database" value="MYSQL" />
                &lt;property name="showSql" value="true" />
            &lt;/bean>
        &lt;/property>
    &lt;/bean>
    
    &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        &lt;property name="driverClassName" value="com.mysql.jdbc.Driver" />
        &lt;property name="url" value="jdbc:mysql://localhost/gmailadmin" />
        &lt;property name="username" value="myweb" />
        &lt;property name="password" value="123456" />
    &lt;/bean>
    
    &lt;bean id="transactionManager"
          class="org.springframework.orm.jpa.JpaTransactionManager">
        &lt;property name="entityManagerFactory" ref="entityManagerFactory" />
    &lt;/bean>
    
    &lt;!--声明式事务配置-->
    &lt;aop:config>
        &lt;aop:pointcut id="allServiceOperation" expression="execution(* com.xxx.xxx.service.*Service.*(..))"/>
        &lt;aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceOperation"/>
    &lt;/aop:config>
    
    &lt;tx:advice id="txAdvice" transaction-manager="transactionManager">   
        &lt;tx:attributes> 
        	&lt;tx:method name="query*" read-only="true" />
            &lt;tx:method name="*" />
        &lt;/tx:attributes>
    &lt;/tx:advice> 
&lt;/beans>
</pre><br />DAO里面直接用@PersistenceContext注释的
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234792" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 14:49:52 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234792</link>
        <guid>http://www.javaeye.com/topic/234792</guid>
      </item>
      <item>
        <title>扩展OSWorkflow(一、引子，从WPS到EOS到中国企业工作流)</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tsylo.javaeye.com">tsylo</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234785" style="color:red;">http://www.javaeye.com/topic/234785</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-size: medium">    几个月前公司有个项目，项目建设内容较为简单，使用Websphere process server(以下简称WPS)建设几条流程。<br /><br />    在该项目前期，我曾经带领一个团队使用wps做了一个项目，这个项目中有八九条流程，在使用wps的过程当中，我发现wps根本不适合做一些复杂的人工审批工作流，ibm软件日趋全球化，但却忽略了很多本土化的东西，譬如说wps，作为金融行业融合企业内部服务的soa总线级产品，其内嵌的ESB根本达不到应有的性能(每笔交易时间)，而作为电信行业流程引擎，却忽略了最重要的中国国情--人工审批。在前几天上海分公司信息化部召开的技术讨论会议中，我就目前公司内部系统中几个技术难点发出提问，ibm的工程师与老板都不知所云。<br /><br />    中外文化差异很大，国外的工作流希望自动化环节更多一些，减少人工参与，降低上行下达过程中人为的，可能造成误差，而中国则不然，中国要求自动化环节少一些，决策都由人来审批，从处长到经理，从经理到分管领导，审批通过还不能作数，要签字盖章，留作日后证据。为什么会有这样的差异，这个问题暂且交给余秋雨之流去论述，我们只讲技术，既然中国企业工作流中讲究的是审批，那问题就来了，人工审批工作流复杂无比，譬如说会签、联签、发散、汇聚、选择下一节点、选择下一节点处理人等等，这都不是一个符合wfmc或bpel标准的工作流就能做出来的，包括最初的普元，几年前来我们公司做技术交流和产品介绍的时候，我们就这些技术难点提出疑问，EOS完全无法满足电信行业需求，于是其回去闭门苦练，一年后再来介绍时，工作流已经基本上能满足99%的审批要求，而WPS刚刚进入中国市场在中国做审批工作流连一个像样的大型成功案例都没有，就更无法满足需求了。<br /><br />    但介于公司内部系统的现状，使用WPS还是有一些benefit的,公司建设内部管理系统使用了Websphere portal，Domino，Tivoli，MQ，MB等软件，在集成展现上使用portal，内部oa使用lotus，统一认证，统一用户管理使用了TAM，TIM，EAI使用了MB，这样如果工作流使用wps的话，至少做一些展现、SSO、UM等都不存在问题，再加上IBM几个销售卖力的忽悠，领导被骗进，公司吃药，使用了wps，秉承技术人员认证负责的态度，用就用了，把它用到最好，是我的责任，于是我进行了一系列的探索，前期使用wps建设时候，由于其无法满足“选择下一节点处理人”的需求，我自己封装了一大堆的代码，补充wps的流程预知功能，等项目结束后，我惊讶的发现，我自己写的那部分代码，居然已经构成了一个小型工作流引擎，汗颜的同时，我也在思考，既然这样，我不然干脆就做一个轻量级的工作流引擎来取代wps的HumanTask组件进行人工审批，让wps发挥其ESB的功能，当系统之间窜接的过程中遇到个别简单的审批，则采用wps本身的人工任务，但如若需要进行复杂的人工审批流程，则进入我自己的轻量级工作流引擎进行审批，我为自己的这个想法感到兴奋、跃跃欲试，接下来的工作就是选型了，目前市面上的工作流引擎很多，普元的，西安协同的，这些都需要购买license，不考虑，开源框架里有jbpm，osworkflow,shark等，经过考虑再三，jbpm和shark过于封闭，不利于改造成适应行业需求的流程引擎，于是采用osworkflow(以下简称os)，自己在os上扩展了一层，我把它叫做ExtOSWorkflow，从取英文首字母来命名简称，变成了EOS，我狂晕，于是不偷懒，我把它叫做ExtOS，在ExtOS中，我扩展改造了很多功能，差不多改掉了除核心以外一半的源码，完成功能包括：完整的待办任务列表、在办任务列表、已办任务列表、流程历史、流程会签、流程回退、流程委派、子流程、流程时限监控，流程版本控制等，其中会签与版本控制功能尚在继续开发，其余的已经实现，总结之余发表篇文章到blog、圈子、论坛，也想借机引起正在做同类产品的同行的讨论，抛砖引玉吧，关于osworkflow的封装，请听下回分解</span>[/size]
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234785" style="color:red;">已有 <strong>1</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 14:10:48 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234785</link>
        <guid>http://www.javaeye.com/topic/234785</guid>
      </item>
      <item>
        <title>HttpClient容易忽视的细节——链接关闭</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://seanhe.javaeye.com">SeanHe</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234759" style="color:red;">http://www.javaeye.com/topic/234759</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod("http://www.apache.org");
try {
  client.executeMethod(method);
  byte[] responseBody = null;
  
  responseBody = method.getResponseBody();
  
} catch (HttpException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
} catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}finally{
  method.releaseConnection();
  
}
</pre><br />大部分人使用HttpClient都是使用类似上面的事例代码，包括Apache官方的例子也是如此。最近我在使用HttpClient是发现一次循环发送大量请求到服务器会导致APACHE服务器的链接被占满，后续的请求便排队等待。<br />我服务器端APACHE的配置<br /><pre name="code" class="java">
Timeout 30
KeepAlive On   #表示服务器端不会主动关闭链接
MaxKeepAliveRequests 100
KeepAliveTimeout 180 
</pre><br />因此这样的配置就会导致每个链接至少要过180S才会被释放，这样在大量请求访问时就必然会造成链接被占满，请求等待的情况。<br />在通过DEBUH后发现HttpClient在method.releaseConnection()后并没有把链接关闭，这个方法只是将链接返回给connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构造函数如下<br /><pre name="code" class="java">
/**
 * The connection manager created with this constructor will try to keep the 
 * connection open (alive) between consecutive requests if the alwaysClose 
 * parameter is set to &lt;tt>false&lt;/tt>. Otherwise the connection manager will 
 * always close connections upon release.
 * 
 * @param alwaysClose if set &lt;tt>true&lt;/tt>, the connection manager will always
 *    close connections upon release.
 */
public SimpleHttpConnectionManager(boolean alwaysClose) {
    super();
    this.alwaysClose = alwaysClose;
}
</pre><br />看方法注释我们就可以看到如果alwaysClose设为true在链接释放之后connection manager 就会关闭链。在我们HttpClient client = new HttpClient()这样实例化一个client时connection manager是这样被实例化的<br /><pre name="code" class="java">
this.httpConnectionManager = new SimpleHttpConnectionManager();
</pre><br />因此alwaysClose默认是false,connection是不会被主动关闭的，因此我们就有了一个客户端关闭链接的方法。<br /><strong>方法一：</strong><br />把事例代码中的第一行实例化代码改为如下即可，在method.releaseConnection();之后connection manager会关闭connection 。<br /><pre name="code" class="java">
HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );
</pre><br /><strong>方法二：</strong><br />实例化代码使用：HttpClient client = new HttpClient();<br />在method.releaseConnection();之后加上<br /><pre name="code" class="java">((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();</pre><br />shutdown源代码很简单，看了一目了然<br /><pre name="code" class="java">
public void shutdown() {
    httpConnection.close();
}
</pre><br /><strong>方法三：</strong><br />实例化代码使用：HttpClient client = new HttpClient();<br />在method.releaseConnection();之后加上<br />client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下：<br /><pre name="code" class="java">
public void closeIdleConnections(long idleTimeout) {
    long maxIdleTime = System.currentTimeMillis() - idleTimeout;
    if (idleStartTime &lt;= maxIdleTime) {
        httpConnection.close();
    }
}
</pre><br />将idleTimeout设为0可以确保链接被关闭。<br />以上这三种方法都是有客户端主动关闭TCP链接的方法。下面再介绍由服务器端自动关闭链接的方法。<br /><strong>方法四：</strong><br />代码实现很简单，所有代码就和最上面的事例代码一样。只需要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP头的设置即可<br /><pre name="code" class="java">
method.setRequestHeader("Connection", "close");
</pre><br />看一下HTTP协议中关于这个属性的定义：<br />HTTP/1.1 defines the "close" connection option for the sender to signal that the connection will be closed after completion of the response. For example, <br />       Connection: close<br />现在再说一下客户端关闭链接和服务器端关闭链接的区别。如果采用客户端关闭链接的方法，在客户端的机器上使用netstat –an命令会看到很多TIME_WAIT的TCP链接。如果服务器端主动关闭链接这中情况就出现在服务器端。<br />参考WIKI上的说明http://wiki.apache.org/HttpComponents/FrequentlyAskedConnectionManagementQuestions<br />The TIME_WAIT state is a protection mechanism in TCP. The side that closes a socket connection orderly will keep the connection in state TIME_WAIT for some time, typically between 1 and 4 minutes.<br />TIME_WAIT的状态会出现在主动关闭链接的这一端。TCP协议中TIME_WAIT状态主要是为了保证数据的完整传输。具体可以参考此文档：<br />http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7<br /><strong>另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用链接时可以主动关闭链接来释放资源。如果你的应用是需要重用链接的话就没必要这么做，使用原有的链接还可以提供性能。</strong>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234759" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 12:22:44 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234759</link>
        <guid>http://www.javaeye.com/topic/234759</guid>
      </item>
      <item>
        <title>给大家介绍一款j2ee的代码生成工具，基于spring的</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://key232323.javaeye.com">key232323</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234522" style="color:red;">http://www.javaeye.com/topic/234522</a>&nbsp;
          发表时间: 2008年08月29日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-size: medium">1.Product introduction</span><br />	<br />	This is a code generator writing by java,which aims at building a web based application quickly,I mean its structure.The application produced takes the form of a eclipse project,what you need to do is only to new a java project in eclipse in the specific directory.Your can refer to the vedio'intro.avi' to see a whole example.<br /><br />	This tool itself is also a eclipse project,it include a open source http server 'pygmy',a tool to generate output files which is mainly based on 'freemarker' template engine,also a web-based GUI<br />module in which your can simply build the aim project.Project's datas are stored in xml file.<br /><br />2.What does it produce?<br />	A web base application.According to j2ee classical and common layered structure:view layer,controller layer,business layer and dao layer.The result mainly can be divided into three parts,java source files,html or vm/ftl pages and configuration files such as spring bean.xml,web.xml,log4j properties and so on.<br />	Techniques related:JSP or Velocity or Freemarker,Spring MVC,Spring IOC and AOP,Spring JDBC or orm like ibatis and hibernate.<br /><br />3.About the vedio<br />	It's just a sample including how to use this tool and how to build a web project quickly.<br /><br />4.At last<br />	It's totally open source and you can get the sources and modify/improve whatever you want.Obviously it has some bugs and problems,but it works and help you get rid of some tedious unimportant jobs.Hope you like it,contact me.
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234522" style="color:red;">已有 <strong>3</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Fri, 29 Aug 2008 16:58:22 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234522</link>
        <guid>http://www.javaeye.com/topic/234522</guid>
      </item>
      <item>
        <title>忘掉普元EOS、构建自己的企业级快速应用开发平台</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://longlongriver.javaeye.com">longlongriver</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/232219" style="color:red;">http://www.javaeye.com/topic/232219</a>&nbsp;
          发表时间: 2008年08月25日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong><span style="font-size: x-small;"><em><span style="color: #ff0000; font-size: small;">希望这篇文章能够对那些正在或即将开发自己团队的J2EE应用快速开发平台（工作流＋代码生成器）的个人或公司能有所启发！</span>
</em>
&nbsp;&nbsp;&nbsp;</span>
</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 像EOS这样动辄几十上百万的平台不是每个公司都愿意花钱去买的！因此构建一套穷人级的企业快速开发平台成了很多团队的首选，而对于小团队来说，构建一套自己可以维护的开发平台才是最重要的。下面，我将以我的平台的开发过程为例来详细解析这个过程！<strong><span style="font-size: x-small;"> &nbsp; </span>
</strong>
</p>
<p><span style="font-size: small;"><strong><span>&ldquo;如果能把项目中大量的代码编写工作变得轻松，是多好的一件事!</span>
</strong>
&nbsp;"</span>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
在使用了AppFuse之后，我有个想法，能不能利用velocity这个优秀的模板引擎，用一种更加直观的模式，把开发项目中的重复代码让它自动生成，
生成之后的基础代码，按照实际的需求稍作修改便可以运行，极大的提高工作效率。这样的话，程序员就可以从大量的重复劳动中解放出来，将精力更多的投入到业
务分析及学习中。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个想法一直在我的脑海里横亘不去，尤其在做了大量的重复模块后，深刻体会了重复Coding的那种浪费生命的痛苦后，这种冲动尤为强烈。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 离开旧公司，到了新公司之后，由于职位和公司定位的不同，让我有时间开始把快速开发平台和自动代码生成器的开发真正的摆上开发日程上了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: medium;"><strong><span style="text-decoration: underline;">第一步</span>
</strong>
</span>
，自动代码生成器生成
的是业务模块，那么底层必须有一套框架能够为它提供支撑，而且这套基础框架要足够灵活，并且和单个模块的耦合性要比较弱。要解耦模块之间的联系，势必要用
到MVC分层设计。感谢Java的开放性，使它有这么许许多多的MVC框架可以使用。我采用的当然是目前最流行的
SSH（Struts＋Spring＋Hibernate）的组合（以前项目一直在用，也有些成熟的积累），花了三个月的时间，通过一个项目的实际应用来
使这个框架基本成型。其目前功能包括：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1：灵活完善的权限管理功能（包括用户管理、角色管理、组织机构管理、资源管理、资源角色映射管理...）。原来计划采用开源的JGuard来托管这部分
的功能，因为一些特殊的原因放弃了（考虑要和工作流引擎的权限部分做集成），只采用了其权限管理的一些设计思想。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2：基于Spring的AOP实现的日志和权限管理（通过Spring的代理也将Struts的Action托管了，使的对Action的调用也能被
AOP侦测到），这样对每个功能的调用，如果需要日志纪录的话，之间将其配置到Spring的配置文件中就可以了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3：UI上实现了类似.NET的Validation验证，这点很重要，想必大家都深刻体会到利用JavaScript或Struts的验证机制来实现前端页面数据验证的痛苦了吧：），我们实现的功能如下图所示：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/1.GIF" alt="" />
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、多套UI风格样式。这个不是很必须，但是作为一套成功的系统，良好的用户体验也是必不可少的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、支撑模块：报表引擎（基于JasperReport实现的B/S版本报表），流程引擎（<span style="color: #ff0000; font-size: large;"><span style="text-decoration: underline;"><strong>其实就我个人来看，工作流引擎才是这套系统的灵魂</strong>
<strong>，有了它，所有流程性应用包括表单、业务流、权限都可以通过配置并结合Beanshell脚本来获得</strong>
</span>
</span>
，但由于我们集成的是一套反编译重构的商用流程引擎系统，在这里就不再详细描述了 ，呵呵：），有盗版之嫌啊）,以下是我们报表和流程设计器的一些截图：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/EntryImages/20080826/workflow2.GIF" height="969" alt="" width="1207" />
</p>
<p>&nbsp;</p>
<p align="center"><strong>工作流引擎截图</strong>
</p>
<p>&nbsp;</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/EntryImages/20080825/report.GIF" alt="" style="width: 904px; height: 441px;" />
</p>
<p align="center"><strong>报表截图</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 6、i18n的支持，由于我们有很多国外的客户，这块是必须的。</p>
<p>&nbsp;</p>
<p>有了这个基础支撑平台之后，就可以开始着手开放我们的代码生成器了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="text-decoration: underline;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp; 第二步</span>
</span>
</strong>
：开发代码生成器。
AppFuse基于Ant的自动代码生成模式让我深恶痛绝，究其原因，一句话－－&ldquo;不够人性化&rdquo;，我们做的首先必须考虑可用性，因此决定采用可视化的UI
模式。由于我用的是NetBean编辑器，做可视化的Swing开发不成问题（这点要感谢SUN啊，出了个和VB一样简单的IDE）。我实现的代码生成器
的界面如下：<img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/2.GIF" height="483" alt="" style="width: 589px; height: 555px;" width="443" />
</p>
<p>&nbsp;&nbsp; <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/3.GIF" alt="" />
</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/4.GIF" alt="" />
</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/5.GIF" alt="" />
</p>
<p>&nbsp; <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/6.GIF" alt="" />
</p>
<p>怎么样？是不是够傻瓜化啊？呵呵，是个人都能用啊！</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
从上面大家可以看到，我们这个代码生成器和Hibernate的POJO对象生成工具类似，也是基于数据库的模型来生成代码的，不同的是，我们生成的代码
范围更广，不仅包括了POJO对象暨相应的hbm.xml文件，另外还包括相应的DAO（Server层）、相应的Action、Form类、相关的
JSP文件（list页面、edit页面、Excel导出页面等等）、资源文件及相关的Struts和Spring的配置子文件（Struts和
Spring均支撑将配置拆分成多个配置，我们利用这种特性来减低模块之间的耦合性。）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 至于数据库模型的获得，可以利用JDBC的<strong><em><span style="text-decoration: underline;">MetaData（元数据模型）</span>
</em>
</strong>
的功能来获得，我们目前维护了表的完整的主键、外键关系（父子表）</p>
<p>&nbsp;第三步：配置模板。有了可视化的数据库表映射模型，也获得了数据库表及其主外键关系的详细信息，接下来当然是根据这些信息来生成代码了。这里我们用了强大的<strong><em><span style="text-decoration: underline;">Velocity模板</span>
</em>
</strong>
技术，这样不仅可以灵活的处理复杂的表映射对象之间的关系，也能够灵活的进行变更升级。<span style="text-decoration: underline;">而且我们能够通过所获得的数据库模型，在页面上自动实现基于Javascript的数据验证&ldquo;非空验证、字符长度验证、数字验证，日期验证&rdquo;。</span>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
呵呵，通过以上3个步骤的工作，我们的基础开发平台和自动代码生成器就大功告成了！目前我们生成的代码可以直接编译通过，通过简单的系统配置后，可以直接在服务器上跑！
由于模板种类多，而且模板中自动实现的代码功能已经非常完善了，所以一些特殊的业务需求只需要在自动生成的代码基础上做简单修改就可以了！</p>
<p><span style="color: #333399; font-size: small;">&nbsp;&nbsp;<strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
基础开发平台和代码生成器投入使用后，对我们项目开发的资源投入的改善是非常明细的，目前基于基础平台和代码生成器的配合，我们已经做了6、7个系统了，平均每个系统的
开发时间至少要比以前节约40％，有的项目甚至达到了80％以上（我们最高的一天，处理了40多个表的增、删、该、查的功能，及中文本地化）。而且，另外
很重要的一点，生成的代码无形中统一了程序员的设计风格，我们通过这套开发机制，能够最大限度的保证我们开发的系统质量，保证模块可以在不同系统之间的自
由迁移，最大限度的实现复用！在项目开发中节省出来的大量时间，也让我们可以去研究更多的开源中间件和系统，来增强我们的基础平台，从而形成一个良性的循
环！</strong>
</span>
</p>
<p>&nbsp;我们做了多套模板，能够针对单表操作，及父子表操作来自由组合搭配。以下就是我们系统的一些功能截图，除了中文化之外，基本上没有修改：</p>
<p><strong><span style="color: #ff0000; font-size: small;">单表操作：</span>
</strong>
</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/7.GIF" alt="" />
</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/8.GIF" alt="" />
</p>
<p><span style="color: #ff0000; font-size: medium;"><strong>父子表关联操作：</strong>
</span>
</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/LongLongRiver/10.GIF" alt="" />
</p>
<p><span style="font-size: small;"><em><strong>&nbsp;</strong>
</em>
</span>
</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/232219" style="color:red;">已有 <strong>76</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Mon, 25 Aug 2008 09:44:43 +0800</pubDate>
        <link>http://www.javaeye.com/topic/232219</link>
        <guid>http://www.javaeye.com/topic/232219</guid>
      </item>
      <item>
        <title>一个关于Hibernate的优化实例：从HQL到QBC，从QBC到QBE，再到“增强的”QBE</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://movingboy.javaeye.com">movingboy</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/233664" style="color:red;">http://www.javaeye.com/topic/233664</a>&nbsp;
          发表时间: 2008年08月28日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          先解释一下标题的含义：为了实现一个组合条件查询，先是使用HQL书写，然后改用Query by Criteria方式，再尝试Query by Example，最后自己实现了一个增强的Example类来解决问题。<br /><br />关于此问题的起源请阅读我以前的一个帖子：<a href="http://www.javaeye.com/post/523791" target="_blank">http://www.javaeye.com/post/523791</a>。在该帖子中已经实现了从HQL到QBC的转变，在这里就不再重复了。<br /><br />在上一个帖子中没有模型类Product及Category的代码，为了方便讨论补充如下：<br /><br /><pre name="code" class="java">public class Category {
  private Long id;
  private String name; //类别名称

  //Other code omitted
}

public class Product {
  private Long id;
  private String name;       //商品名称
  private Category category; //商品类别
  private Date expDate;      //有效期
  private Float price;       //单价

  //Other code omitted
}
</pre><br /><br />从前一个帖子中可以看到，使用QBC后代码有所减少，但还是得把构造查询条件的代码写死，这非常不爽。重读了《Java Persistence with Hibernate》一书，发觉QBE是个好东东，于是尝试用改造代码如下：<br /><br /><pre name="code" class="java">	public List&lt;Product> getProducts(Product product) {
		final Example exampleProduct =
		  Example.create(product).
		    enableLike(MatchMode.ANYWHERE).
                    excludeZeroes();

		return (List&lt;Product>) getHibernateTemplate().execute(
		  new HibernateCallback() {
		    public Object doInHibernate(Session session) throws HibernateException {
		    	Criteria crit =
		    	  session.createCriteria(Product.class).
		    	  add(exampleProduct);
		    	return crit.list();
		    }
		  }
		);
	}
</pre><br /><br />代码非常简洁啊！我只要new一个Product实例，然后把要查询的条件值赋值到相应到属性上，如果某项条件未指定则相应的属性保留为默认的空值，将该实例传递给上面的getProducts方法，就能得到需要的结果了。超爽！<br /><br />但是我却没办法把这段代码用在产品中，这是因为QBE有着严重的局限性：<br />1.不能查询指定在关联对象的属性上的条件。比如我想仅列出商品类别名称包括xyz的商品，代码如下：<br /><br /><pre name="code" class="java">Category category = new Category();
category.setName("xyz");
Product product = new Product();
product.setCategory(category);

List&lt;Product> products = getProducts(product);
</pre><br /><br />运行这段代码会列出所有的商品。<br /><br />2.除了字符串条件可以调用enableLike()方法改用模糊查询外，其它数据类型的条件都只能等值比较。比如我无法查询所有有效的商品（有效期≥当前日期）。<br /><br />难道就没有办法了吗？经过一番搜索，终于在Hibernate的官网论坛上找到一篇文章：<a href="http://forum.hibernate.org/viewtopic.php?t=942872" target="_blank">http://forum.hibernate.org/viewtopic.php?t=942872</a>。在该文章中，Dencel写了一个AssociationExample，经过大家的完善，终于解决了查询指定在关联对象的属性上的条件的问题。其主要的奥妙在于：<br /><br /><pre name="code" class="java">
//Hibernate的原版Example
//如果属性类型是关联的实体，则忽略
	private boolean isPropertyIncluded(Object value, String name, Type type) {
		return !excludedProperties.contains(name) &&
			!type.isAssociationType() &&
			selector.include(value, name, type);
	}

//改版的AssociationExample
  private boolean includeAssociations = true;

  public boolean isIncludeAssociations()
  {
    return includeAssociations;
  }

  public void setIncludeAssociations(boolean includeAssociations)
  {
    this.includeAssociations = includeAssociations;
  }

//如果属性类型是关联的实体，且该关联是一对一或多对一，且includeAssociations为true，则包括该属性
  private boolean isPropertyIncluded(Object value, String name, Type type) {
    return
      !excludedProperties.contains(name) &&
      selector.include(value, name, type) &&
      (!type.isAssociationType() ||
        (type.isAssociationType() &&
          includeAssociations &&
          !type.isCollectionType()));
  }
</pre><br /><br />解决了前面提到的第一个问题，第二个问题又怎么办呢？我想到一个办法：如果某个条件要使用其它的比较方式（比如大于等于），提供一个方法让用户为该属性指定比较方法，对于其它属性仍采用缺省的查询/比较方法：<br /><br /><pre name="code" class="java">
//Hibernate原版的Example
  protected void appendPropertyCondition(
    String propertyName,
    Object propertyValue,
    Criteria criteria,
    CriteriaQuery cq,
    StringBuffer buf)
  throws HibernateException {
    Criterion crit;
    if ( propertyValue!=null ) {
//当属性值不为空时，如果是字符串且指定为模糊查询，则使用模糊查询，否则使用等值比较
      boolean isString = propertyValue instanceof String;
      SimpleExpression se = ( isLikeEnabled && isString ) ?
        Restrictions.like(propertyName, propertyValue) :
        Restrictions.eq(propertyName, propertyValue);
      crit = ( isIgnoreCaseEnabled && isString ) ?
        se.ignoreCase() : se;
    }
    else {
      crit = Restrictions.isNull(propertyName);
    }
    String critCondition = crit.toSqlString(criteria, cq);
    if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
    buf.append(critCondition);
  }


//增强后的EnhancedExample
  private static final RestrictionHolder holder = new DefaultRestrictionHolder();

  /**
   * Restriction strategy definitions
   */
  public static enum RestrictionStrategy {eq, ne, gt, lt, ge, le}

  /**
   * Restriction strategy holder for the query criteria
   */
  public static interface RestrictionHolder {
  	/**
  	 * Set a restriction strategy for a POJO's property
  	 */
    public RestrictionHolder set(String propertyName, RestrictionStrategy strategy);

    /**
     * Get the restriction strategy of the property
     */
    public RestrictionStrategy get(String propertyName);
  }

  static final class DefaultRestrictionHolder implements RestrictionHolder {
		private Map&lt;String, RestrictionStrategy> strategies = new HashMap&lt;String, RestrictionStrategy>();

    public RestrictionHolder set(String propertyName, RestrictionStrategy strategy) {
      strategies.put(propertyName, strategy);
      return this;
    }

    public RestrictionStrategy get(String propertyName) {
      return strategies.get(propertyName);
    }
  }

  /**
   * Get the restriction strategy holder
   */
  public RestrictionHolder getRestrictionHolder() {
    return holder;
  }

  protected void appendPropertyCondition(
    String propertyName,
    Object propertyValue,
    Criteria criteria,
    CriteriaQuery cq,
    StringBuffer buf)
  throws HibernateException {
    Criterion crit;
    if ( propertyValue!=null ) {
//当属性值不为空时，如果为该属性指定了比较条件，则使用指定的比较条件
      RestrictionStrategy strategy = holder.get(propertyName);
      if ( strategy != null ) {
  	switch(strategy) {
    	//case eq: crit = Restrictions.eq(propertyName, propertyValue);
    	case ne: crit = Restrictions.ne(propertyName, propertyValue); break;
    	case gt: crit = Restrictions.gt(propertyName, propertyValue); break;
    	case lt: crit = Restrictions.lt(propertyName, propertyValue); break;
    	case ge: crit = Restrictions.ge(propertyName, propertyValue); break;
    	case le: crit = Restrictions.le(propertyName, propertyValue); break;
    	default: crit = Restrictions.eq(propertyName, propertyValue);
        };
      }
      else {
//否则使用默认的比较条件：如果是字符串且指定为模糊查询，则使用模糊查询，否则使用等值比较
	boolean isString = propertyValue instanceof String;
	SimpleExpression se = ( isLikeEnabled && isString ) ?
	  Restrictions.like(propertyName, propertyValue) :
	  Restrictions.eq(propertyName, propertyValue);
	crit = ( isIgnoreCaseEnabled && isString ) ?
	  se.ignoreCase() : se;
      }
    }
    else {
      crit = Restrictions.isNull(propertyName);
    }
    String critCondition = crit.toSqlString(criteria, cq);
    if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
    buf.append(critCondition);
  }
</pre><br /><br />于是前面getProducts方法只需要简单修改一下：<br /><br /><pre name="code" class="java">	public List&lt;Product> getProducts(Product product) {
		//改用EnhancedExample来允许关联对象的条件查询
		final EnhancedExample exampleProduct =
		  EnhancedExample.create(product).
		    enableLike(MatchMode.ANYWHERE).
                    excludeZeroes();
		  //指定expDate属性使用大于等于比较方法
		exampleProduct.getRestrictionHolder().
		  set("expDate", EnhancedExample.RestrictionStrategy.ge);

		return (List&lt;Product>) getHibernateTemplate().execute(
		  new HibernateCallback() {
		    public Object doInHibernate(Session session) throws HibernateException {
		    	Criteria crit =
		    	  session.createCriteria(Product.class).
		    	  add(exampleProduct);
		    	return crit.list();
		    }
		  }
		);
	}
</pre><br /><br />经过以上改进，QBE的实用性大大提高，能够真正解决较大多数的组合查询问题。<br /><br />已知的问题：以上“增强的”QBE还无法解决范围查询（比如价格在0到1000之间），这是因为一个属性只能携带一个值（你不可能指定两个值给Product.price属性）。这种情况下需要修改getProducts方法，增加参数把价格范围传递进来，再以QBC方式把相应的条件加到crit变量上。范例代码就不再给出了。<br /><br />完整的EnhancedExample源码请见附件。
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/233664" style="color:red;">已有 <strong>22</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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, 28 Aug 2008 00:04:40 +0800</pubDate>
        <link>http://www.javaeye.com/topic/233664</link>
        <guid>http://www.javaeye.com/topic/233664</guid>
      </item>
      <item>
        <title>SDO之类型不匹配的问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://marb.javaeye.com">marb</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234701" style="color:red;">http://www.javaeye.com/topic/234701</a>&nbsp;
          发表时间: 2008年08月30日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>由于工作的原因，接触了SDO，在研发的过程中遇到很多类型转换方面的问题，网上相应的中文资料比较少，自己总结了一些tip，希望对大家有所帮助</p>
<p>&nbsp;</p>
<p>将一个DataObject赋予另一个同schema生成的DataObject时，报</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">Exception in thread &quot;main&quot; java.lang.ClassCastException: The feature 'ReceiveOrder's type 
'ReceiveOrder' does not permit a 
value of type 'ReceiveOrder'
	at org.eclipse.emf.ecore.impl.EStructuralFeatureImpl$BasicFeatureMapEntry.
validate(EStructuralFeatureImpl.java:2843)
	at org.eclipse.emf.ecore.util.FeatureMapUtil.createEntry(FeatureMapUtil.java:146)
	at org.eclipse.emf.ecore.util.BasicFeatureMap.createEntry(BasicFeatureMap.java:94)
	at org.eclipse.emf.ecore.util.BasicFeatureMap.set(BasicFeatureMap.java:1051)
	at org.eclipse.emf.ecore.util.FeatureMapUtil$FeatureValue.set(FeatureMapUtil.java:1149)
	at org.eclipse.emf.ecore.impl.EStructuralFeatureImpl$InternalSettingDelegateFeatureMapDelegator
.dynamicSet(EStructuralFeatureImpl.java:1401)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eDynamicSet(BasicEObjectImpl.java:709)
	at org.apache.tuscany.sdo.impl.DynamicDataObjectImpl.eDynamicSet(DynamicDataObjectImpl.java:160)
	at org.apache.tuscany.sdo.impl.DataObjectImpl.eSet(DataObjectImpl.java:1476)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eSet(BasicEObjectImpl.java:654)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:204)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:160)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:167)
	at org.apache.tuscany.sdo.helper.XMLHelperImpl.save(XMLHelperImpl.java:168)
	at org.apache.tuscany.sdo.helper.XMLHelperImpl.save(XMLHelperImpl.java:130)</pre>
<p>&nbsp;我们看下试验的代码：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">//从字符串创造DataObject
                String dataObjectStr = 
			 &quot;&lt;m:ReceiveOrder xmlns:m=\&quot;http://ordertomanufacturingservice.services.starflow.ro.icss.com/wsdl\&quot;&gt;&quot; +
			       &quot;&lt;orderId&gt;testreciiveServcice11111&lt;/orderId&gt;&quot; +
			       &quot;&lt;customerId&gt;String&lt;/customerId&gt;&quot; +
			       &quot;&lt;customerName&gt;String&lt;/customerName&gt;&quot; +
			       &quot;&lt;orderItems&gt;&quot; +
			          &quot;&lt;orderItem&gt;	&quot; +
			             &quot;&lt;productName&gt;String&lt;/productName&gt;&quot; +
			             &quot;&lt;price&gt;3.1415926535897932384626433832795&lt;/price&gt;&quot; +
			             &quot;&lt;quantity&gt;String&lt;/quantity&gt;&quot; +
			             &quot;&lt;comment&gt;String&lt;/comment&gt;&quot; +
			             &quot;&lt;shipDate&gt;String&lt;/shipDate&gt;	&quot; +
			           &quot;&lt;/orderItem&gt;&quot; +
			        &quot;&lt;/orderItems&gt;&quot; +
			  &quot;&lt;/m:ReceiveOrder&gt;&quot;;

                //创造第一个DataObject
		 HelperContext scope =  SDOUtil.createHelperContext();
		 loadTypesFromXMLSchemaStr(scope,schema3);
		 XMLDocument xmlDoc = getXMLDocumentFromString(scope,dataObjectStr);
		 DataObject root = xmlDoc.getRootObject();
		 
		//创造第二个DataObject
		 HelperContext scope2 =  SDOUtil.createHelperContext();
		 DataObject obj = createRootDataObject(scope2,schema3,&quot;ReceiveOrder&quot;);
		 
		 //将第一个DO赋予第二个DO
		 obj = root;
		 String xmlstr = scope2.getXMLHelper().save(obj, getNameSpaceFromSchema(schema3), 
                      &quot;ReceiveOrder&quot;);
		 System.out.println(xmlstr);

              /**
	        * 从字符串中获取XMLDocument对象
	        * @param scope
	        * @param xmlDoc
	        * @return
	        * @throws IOException
	        */
               private static XMLDocument getXMLDocumentFromString(HelperContext scope, 
                        String xmlDoc) throws IOException {
		InputStream is = new ByteArrayInputStream(xmlDoc.getBytes());
		XMLDocument result = scope.getXMLHelper().load(is);
		return result;
	       }

            /**
	      * 创建文档的顶层DO
	      * @param schemaStr
	      * @param type
	      * @return
	      * @throws UnsupportedEncodingException
	      * @throws FileNotFoundException
	      */
             private static DataObject createRootDataObject(HelperContext scope,String schemaStr
                    ,String type) throws UnsupportedEncodingException, FileNotFoundException{
		loadTypesFromXMLSchemaStr(scope,schemaStr);
		DataFactory factory = scope.getDataFactory();         
		DataObject root = factory.create(getNameSpaceFromSchema(schemaStr),type);
		return root;
	      }
                </pre>
<p>&nbsp;打印结果如下：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">Exception in thread &quot;main&quot; java.lang.ClassCastException: The feature 'ReceiveOrder's type
 'ReceiveOrder' does not permit a value of type 'ReceiveOrder'
	at org.eclipse.emf.ecore.impl.EStructuralFeatureImpl$BasicFeatureMapEntry
.validate(EStructuralFeatureImpl.java:2843)
	at org.eclipse.emf.ecore.util.FeatureMapUtil.createEntry(FeatureMapUtil.java:146)
	at org.eclipse.emf.ecore.util.BasicFeatureMap.createEntry(BasicFeatureMap.java:94)
	at org.eclipse.emf.ecore.util.BasicFeatureMap.set(BasicFeatureMap.java:1051)
	at org.eclipse.emf.ecore.util.FeatureMapUtil$FeatureValue.set(FeatureMapUtil.java:1149)
	at org.eclipse.emf.ecore.impl.EStructuralFeatureImpl$InternalSettingDelegateFeatureMapDelegator
.dynamicSet(EStructuralFeatureImpl.java:1401)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eDynamicSet(BasicEObjectImpl.java:709)
	at org.apache.tuscany.sdo.impl.DynamicDataObjectImpl.eDynamicSet(DynamicDataObjectImpl.java:160)
	at org.apache.tuscany.sdo.impl.DataObjectImpl.eSet(DataObjectImpl.java:1476)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eSet(BasicEObjectImpl.java:654)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:204)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:160)
	at org.apache.tuscany.sdo.helper.XMLDocumentImpl.save(XMLDocumentImpl.java:167)
	at org.apache.tuscany.sdo.helper.XMLHelperImpl.save(XMLHelperImpl.java:168)
	at org.apache.tuscany.sdo.helper.XMLHelperImpl.save(XMLHelperImpl.java:130)
	at com.icss.ro.starflow.service.mappingservice.Test2.main(Test2.java:305)</pre>
&nbsp;
<p>这就奇怪了，我明明用同样的schema创建的两个对象，按照java中最基本的赋值原则，我这样直接给DO赋值也应该没错啊，百思不得其解。仔细观察发现，两个DO虽然属于同一个schema，但隶属于不同的HelperContext,问题会不会出在这里呢，我们再试验下，代码修改为：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">               //创造第一个DataObject
		 HelperContext scope =  SDOUtil.createHelperContext();
		 loadTypesFromXMLSchemaStr(scope,schema3);
		 XMLDocument xmlDoc = getXMLDocumentFromString(scope,dataObjectStr);
		 DataObject root = xmlDoc.getRootObject();
		 
		//创造第二个DataObject
		 HelperContext scope2 =  SDOUtil.createHelperContext();
		 DataObject obj = createRootDataObject(scope,schema3,&quot;ReceiveOrder&quot;);
		 
		 //将第一个DO赋予第二个DO
		 obj = root;
		 String xmlstr = scope.getXMLHelper().save(obj, getNameSpaceFromSchema(schema3), 
                      &quot;ReceiveOrder&quot;);
		 System.out.println(xmlstr);

</pre>
&nbsp;
<p>这时的打印结果为：</p>
<p>&nbsp;</p>
<pre name="code" class="java">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;tns:ReceiveOrder xmlns:tns=&quot;http://ordertomanufacturingservice.services.starflow.ro.icss.com/wsdl&quot;&gt;
  &lt;orderId&gt;testreciiveServcice11111&lt;/orderId&gt;
  &lt;customerId&gt;String&lt;/customerId&gt;
  &lt;customerName&gt;String&lt;/customerName&gt;
  &lt;orderItems&gt;
    &lt;orderItem&gt;
      &lt;productName&gt;String&lt;/productName&gt;
      &lt;price&gt;3.1415926535897932384626433832795&lt;/price&gt;
      &lt;quantity&gt;String&lt;/quantity&gt;
      &lt;comment&gt;String&lt;/comment&gt;
      &lt;shipDate&gt;String&lt;/shipDate&gt;
    &lt;/orderItem&gt;
  &lt;/orderItems&gt;
&lt;/tns:ReceiveOrder&gt;
</pre>
&nbsp;
<p>通过这个例子，我们发现，如果要给两个DO赋值的话，它不单要隶属于同一个xsd文件的同一个类型，而且还要隶属同一个HelperConetxt,否则就要报如上的异常了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234701" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Sat, 30 Aug 2008 03:29:31 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234701</link>
        <guid>http://www.javaeye.com/topic/234701</guid>
      </item>
      <item>
        <title>工厂模式运用-锻造武器</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://everlive.javaeye.com">40020072</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/233420" style="color:red;">http://www.javaeye.com/topic/233420</a>&nbsp;
          发表时间: 2008年08月27日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="color: #003366;"><span style="color: #003366;"><strong>目标</strong></span>：使用一些材料，在一座城市打造出一把武器</span></p>
<p>&nbsp;</p>
<p><span style="color: #003366;"><span style="color: #003366;"><strong>包含元素</strong></span>：</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一、锻造材料：</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、 源生材料:&nbsp;</span><span style="color: #008000;"> <span style="color: #008000;">源生火焰<img src="http://www.javaeye.com/upload/picture/pic/20685/6c7e1cd2-3952-3574-828a-869c9af9e720-thumb.jpg?1219827073" height="37" alt="" width="38" />&nbsp;&nbsp; 源生空气<img src="http://www.javaeye.com/upload/picture/pic/20691/736c8b84-61c7-30d7-923b-b260b0fbcf96-thumb.jpg?1219827159" height="37" alt="" width="39" />&nbsp;&nbsp; 源生法力<img src="http://www.javaeye.com/upload/picture/pic/20693/ead69ef6-8121-3941-8d61-ae4421ae03a4-thumb.jpg?1219827230" height="37" alt="" width="38" />&nbsp;&nbsp;&nbsp; 源生之土<img src="http://www.javaeye.com/upload/picture/pic/20695/cd5d6a83-1a38-30b1-aed8-d055fa614fdd-thumb.jpg?1219827344" height="37" alt="" width="38" /></span></span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、 矿石：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">氪金锭&nbsp;&nbsp; <img src="http://www.javaeye.com/upload/picture/pic/20699/01e03adf-c6a1-3b07-a723-6a6abf424a28-thumb.jpg?1219827508" height="38" alt="" width="38" />&nbsp;&nbsp;&nbsp; 恒金锭 &nbsp;<img src="http://www.javaeye.com/upload/picture/pic/20697/3ccd64d8-dabe-3774-973e-2dde77b1a2f0-thumb.jpg?1219827464" height="39" alt="" width="38" /></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #003366;">&nbsp;3、 药水：</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008000;">超级活力药水<img src="http://www.javaeye.com/upload/picture/pic/20715/8c4abc11-ff4a-33a4-b70a-eda64ebaf69d-thumb.jpg?1219836313" height="40" alt="" width="38" />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000;">&nbsp; </span><span style="color: #008000;">魔能法力药水</span><img src="http://www.javaeye.com/upload/picture/pic/20717/c1358477-f37b-3f26-943b-5456033b1bc3-thumb.jpg?1219836423" height="39" alt="" width="38" /></span></p>
<p>&nbsp;</p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、锻造成品：</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、 双手锤：&nbsp;&nbsp; <span style="color: #b406da;">雷霆</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.javaeye.com/upload/picture/pic/20701/c6093816-2fe1-3a0a-8f02-395a582ef129-thumb.jpg?1219827802" height="37" alt="" width="38" /></span></p>
<p>&nbsp;</p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、&nbsp;单手锤：&nbsp;&nbsp;&nbsp;<span style="color: #b406da;">龙拳之锤</span>&nbsp; &nbsp;<img src="http://www.javaeye.com/upload/picture/pic/20705/40e8c093-5578-3359-89b2-e0002677739b-thumb.jpg?1219827930" height="39" alt="" width="38" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp; </span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、锻造地点：</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、奥格瑞玛&nbsp; </span></p>
<p>&nbsp;&nbsp;&nbsp;<span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、暴风城</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、沙塔斯</span></p>
<p>&nbsp;</p>
<p><span style="color: #003366;"><strong>主要逻辑</strong>：1、锻造一把武器需要不同数量的材料：</span><span style="color: #b406da;">雷霆</span><span style="color: #003366;">需要3种材料（源生材料、矿石、药水）</span></p>
<p>&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #b406da;">龙拳之锤<span style="color: #003366;">需要2种材料（源生材料、矿石）</span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #003366;">&nbsp;2、不同城市锻造武器需要的材料不同：例如：奥格瑞玛(氪金、原生空气、超级活力药水)</span></p>
<p><span style="color: #003366;">&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;&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;&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; 沙塔斯(恒金、原生之火、魔能法力药水)</span></p>
<p><span style="color: #003366;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、运用抽象工厂模式和工厂方法模式</span></p>
<p>&nbsp;</p>
<p><span style="color: #003366;"><strong>主要代码</strong>：</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;</p>
<pre name="code" class="java">/*  
 * 抽象工厂接口，负责创建原材料  
 * 运用抽象工厂模式  
 * 原材料包括 矿石类：Ore  
 *          源生类：Primal  
 *          药水类：Potion  
 */  
public interface CityIngredientFactory {   
    public Primal createPrimal();   
    public Ore createOre();   
    public Potion createPotion();   
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 实现抽象材料工厂  
 * 在暴风城锻造城所需要的材料  
 * 氪金　+　原生之火 +　超级活力药水  
 */  
public class CityStormwindFactory implements CityIngredientFactory {   
    //氪金   
    public Ore createOre() {   
        return new OreKrypton();   
    }   
    //原生之火   
    public Primal createPrimal() {   
        return new PrimalMana();   
    }   
    //超级活力药水   
    public Potion createPotion() {   
        return new PotionRed();   
    }   
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 实现抽象材料工厂  
 * 在沙塔斯锻造城所需要的材料  
 */  
public class CityShattrathFactory implements CityIngredientFactory {   
    //恒金   
    public Ore createOre() {   
        return new OreEternium();   
    }   
    //原生之火   
    public Primal createPrimal() {   
        return new PrimalFire();   
    }   
    //魔能法力药水   
    public Potion createPotion() {   
        return new PotionGreen();   
    }   
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 实现抽象材料工厂  
 * 在奥格瑞玛锻造所需要的材料  
 */  
public class CityOrgrimmarFactory implements CityIngredientFactory {   
    //氪金   
    public Ore createOre() {   
        return new OreKrypton();   
    }   
    //原生空气   
    public Primal createPrimal() {   
        return new PrimalAir();   
    }   
    //超级活力药水   
    public Potion createPotion() {   
        return new PotionRed();   
    }   
  
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="color: #003366;"><strong>以上工厂类已经就绪。</strong></span></p>
<p><strong><span style="color: #003366;">下面开始写武器类</span></strong></p>
<p><strong></strong></p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 工厂类已经就绪，准备武器用到的材料  
 * 要锻造的武器的抽象基类  
 */  
public abstract class Weapon {   
    protected String weaponName;   
    //制作武器将用到的原料   
    protected Ore ore;   
    protected Primal primal;   
    protected Potion potion;   
    //抽象方法用来收集来自“材料工厂”的材料，在子类中实现   
    public abstract void prepare();   
       
    public void makeUp()   
    {   
        System.out.println("==========准备锻造==========");   
    }   
  
    public void make()   
    {   
        System.out.println("==========开始锻造==========");   
        System.out.println("放入材料：");   
        System.out.println("         " + ore.toString());      
        System.out.println("         " + primal.toString());   
        if(null!=potion){   
            System.out.println("         " + potion.toString());   
        }   
    }   
    public void makeEnd()   
    {   
        System.out.println("锻造成品：");   
        System.out.println("         " + this.getWeaponName());    
        System.out.println("==========锻造结束==========");   
    }   
  
    public String getWeaponName() {   
        return weaponName;   
    }   
  
    public void setWeaponName(String weaponName) {   
        this.weaponName = weaponName;   
    }   
       
       
}  
</pre>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 继承自武器的抽象基类  
 * 锻造-龙拳之锤-  
 */  
public class WeaponDragon extends Weapon{   
    CityIngredientFactory cityIngredientFactory;   
    //构造函数中取得一个工厂并储存到一个实例变量中   
    public WeaponDragon(CityIngredientFactory cityIngredientFactory)   
    {   
        this.cityIngredientFactory = cityIngredientFactory;    
    }   
    //覆盖父类方法，获得“材料工厂”的对应的材料对象   
    @Override  
    public void prepare() {   
        //从材料工厂得到正确的材料   
        //龙拳之锤需要2种材料   
        this.ore = cityIngredientFactory.createOre();   
        this.primal = cityIngredientFactory.createPrimal();   
        this.weaponName = "龙拳之锤";   
    }   
}  
</pre>
<p>&nbsp;&nbsp;</p>
<pre name="code" class="java">/*  
 * 继承自武器的抽象基类  
 * 锻造-雷霆-  
 */  
public class WeaponWrath extends Weapon {   
    CityIngredientFactory cityIngredientFactory;   
    //构造函数中取得一个工厂并储存到一个实例变量中   
    public WeaponWrath(CityIngredientFactory cityIngredientFactory)   
    {   
        this.cityIngredientFactory = cityIngredientFactory;    
    }   
  
    @Override  
    public void prepare() {   
        //从材料工厂得到正确的材料   
        //雷霆需要3种材料   
        this.ore = cityIngredientFactory.createOre();   
        this.primal = cityIngredientFactory.createPrimal();   
        this.potion =  cityIngredientFactory.createPotion();   
        this.weaponName = "雷霆";   
    }   
  
}  
</pre>
<p>&nbsp;</p>
<p><span style="color: #003366;"><strong>下面开始打造武器。<br />在不同的城市、打造需要的材料不同</strong></span></p>
<p><strong></strong>&nbsp;</p>
<pre name="code" class="java">/*  
 * 抽象基类  
 */  
public abstract class ForgeWeapon {   
    //武器的实例   
    Weapon weapon;   
    public void forgeWeaponNow(String weaponType)   
    {   
        weapon = createforgeWeapon(weaponType);   
        weapon.prepare();   
        //锻造步骤   
        weapon.makeUp();   
        weapon.make();   
        weapon.makeEnd();   
    }   
    /*  
     * 实例化在子类进行 运用了工厂方法模式  
     */  
    protected abstract Weapon createforgeWeapon(String city);   
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 奥瑞格玛锻造  
 */  
public class OrgrimmarForgeWeapom extends ForgeWeapon {   
    @Override  
    protected Weapon createforgeWeapon(String type) {   
        Weapon weapon;   
        //因为是在奥瑞格玛锻造，所以实例化一个奥瑞格玛的材料工厂   
        CityIngredientFactory cityIngredientFactory = new CityOrgrimmarFactory();   
        System.out.println("==============您在奥格瑞玛锻造============");   
        //根据传入参数判断锻造哪种武器   
        if(type == "Dragon" || "Dragon".equals(type))   
        {   
            weapon = new WeaponDragon(cityIngredientFactory);   
               
            return weapon;   
        }   
        else if(type == "Wrath" || "Wrath".equals(type))   
        {   
            weapon = new WeaponWrath(cityIngredientFactory);   
            return weapon;   
        }   
        return null;   
    }   
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 沙塔斯城锻造  
 */  
public class ShattrathForgeWeapom extends ForgeWeapon {   
    @Override  
    protected Weapon createforgeWeapon(String type) {   
        Weapon weapon;   
        //因为是在沙塔斯城锻造，所以实例化一个沙塔斯城的材料工厂   
        CityIngredientFactory cityIngredientFactory = new CityShattrathFactory();   
        System.out.println("==============您在沙塔斯城锻造============");   
        //根据传入参数判断锻造哪种武器   
        if(type == "Dragon" || "Dragon".equals(type))   
        {   
            weapon = new WeaponDragon(cityIngredientFactory);   
               
            return weapon;   
        }   
        else if(type == "Wrath" || "Wrath".equals(type))   
        {   
            weapon = new WeaponWrath(cityIngredientFactory);   
            return weapon;   
        }   
        return null;   
    }   
       
}  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 暴风城锻造  
 */  
public class StormwindForgeWeapom extends ForgeWeapon {   
       
    @Override  
    protected Weapon createforgeWeapon(String type) {   
        Weapon weapon;   
        //因为是在暴风城锻造，所以实例化一个暴风城的材料工厂   
        CityIngredientFactory cityIngredientFactory = new CityStormwindFactory();   
        System.out.println("==============您在暴风城锻造============");   
        //根据传入参数判断锻造哪种武器   
        if(type == "Dragon" || "Dragon".equals(type))   
        {   
            weapon = new WeaponDragon(cityIngredientFactory);   
               
            return weapon;   
        }   
        else if(type == "Wrath" || "Wrath".equals(type))   
        {   
            weapon = new WeaponWrath(cityIngredientFactory);   
            return weapon;   
        }   
        return null;   
    }   
       
}  
</pre>
<p>&nbsp;</p>
<p><strong></strong>&nbsp;</p>
<p><strong></strong>&nbsp;</p>
<p><strong><span style="color: #003366;">&nbsp;测试类:</span></strong></p>
<p>&nbsp;</p>
<pre name="code" class="java">/*  
 * 锻造武器测试类  
 */  
public class makeWeaponTest extends TestCase {   
    ForgeWeapon forgeWeapon1;   
    ForgeWeapon forgeWeapon2;   
    ForgeWeapon forgeWeapon3;      
    ForgeWeapon forgeWeapon4;   
    //初始化   
    @Override  
    protected void setUp() throws Exception {      
        forgeWeapon1 = new OrgrimmarForgeWeapom();   
        forgeWeapon2 = new ShattrathForgeWeapom();   
        forgeWeapon3 = new ShattrathForgeWeapom();   
        forgeWeapon4 = new StormwindForgeWeapom();   
        System.out.println("*********测试开始*********");                  
    }   
       
    @Override  
    protected void tearDown() throws Exception {   
        System.out.println("*********测试结束*********\n");   
    }   
       
    public  void testforgeWeapon1()   
    {   
        System.out.println("测试1:奥格瑞玛锻造 龙拳之锤");   
        forgeWeapon1.forgeWeaponNow("Dragon");   
    }   
  
    public  void testforgeWeapon2()   
    {   
        System.out.println("测试2:沙塔斯城锻造 龙拳之锤");   
        forgeWeapon2.forgeWeaponNow("Dragon");   
    }   
       
    public  void testforgeWeapon3()   
    {   
        System.out.println("测试3:沙塔斯城锻造 雷霆");   
        forgeWeapon3.forgeWeaponNow("Wrath");   
    }   
       
    public  void testforgeWeapon4()   
    {   
        System.out.println("测试4:暴风城锻造 雷霆");   
        forgeWeapon4.forgeWeaponNow("Wrath");   
    }   
}  
</pre>
<p>&nbsp;<br /><span style="color: #003366;"><strong>测试打印:</strong></span></p>
<pre name="code" class="java">*********测试开始*********   
测试1:奥格瑞玛锻造 龙拳之锤   
==============您在奥格瑞玛锻造============   
==========准备锻造==========   
==========开始锻造==========   
放入材料：   
         氪金   
         源生空气   
锻造成品：   
         龙拳之锤   
==========锻造结束==========   
*********测试结束*********   
  
*********测试开始*********   
测试2:沙塔斯城锻造 龙拳之锤   
==============您在沙塔斯城锻造============   
==========准备锻造==========   
==========开始锻造==========   
放入材料：   
         恒金   
         源生火焰   
锻造成品：   
         龙拳之锤   
==========锻造结束==========   
*********测试结束*********   
  
*********测试开始*********   
测试3:沙塔斯城锻造 雷霆   
==============您在沙塔斯城锻造============   
==========准备锻造==========   
==========开始锻造==========   
放入材料：   
         恒金   
         源生火焰   
         魔能法力药水   
锻造成品：   
         雷霆   
==========锻造结束==========   
*********测试结束*********   
  
*********测试开始*********   
测试4:暴风城锻造 雷霆   
==============您在暴风城锻造============   
==========准备锻造==========   
==========开始锻造==========   
放入材料：   
         氪金   
         源生法力   
         超级活力药水   
锻造成品：   
         雷霆   
==========锻造结束==========   
*********测试结束********* </pre>
<p>&nbsp;</p>
<p><span style="color: #003366;">
<p>&nbsp;</p>
<p><span style="color: #003366;">知识点：</span></p>
<p><span style="color: #003366;">工厂方法模式：定义了一个创建对象的接口，但由子类决定要实例化的类是哪一个，工厂方法让类把实例化推迟到子类。</span></p>
<p><span style="color: #003366;">
<p><span style="color: #003366;">抽象工厂模式：提供一个接口，用于创建相关或依赖对象的家族，而不需要明确指定具体类。（抽象工厂允许客户使用抽象的接口来创建一组相关的产品，而不需要知道</span>或关心实际产出的具体产品是什么，这样一来，客户就从具体的产品被解耦）</p>
</span></p>
<p>&nbsp;</p>
</span></p>
<p>&nbsp;</p>
<p>水平有限差错在所难免 欢迎提出问题</p>
<p>本文注重的是设计模式的运用，不是探讨游戏开发，请读者注意主题</p>
<p>代码下载在<a href="http://everlive.javaeye.com/blog/233138">http://everlive.javaeye.com/blog/233138</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/233420" style="color:red;">已有 <strong>4</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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, 27 Aug 2008 20:39:19 +0800</pubDate>
        <link>http://www.javaeye.com/topic/233420</link>
        <guid>http://www.javaeye.com/topic/233420</guid>
      </item>
      <item>
        <title>将业务逻辑封入数据库的SP中是良好的解决之道么？</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://iheshi.javaeye.com">iheshi</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234245" style="color:red;">http://www.javaeye.com/topic/234245</a>&nbsp;
          发表时间: 2008年08月29日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          最近开始接手一个维护性项目。由于项目已经年久失修，公司已经另起炉灶，准备新建一系统来代替目前的这个旧系统。不过在构建的过程中，因为公司的业务逻辑不能中断，所以还是需要继续维护这个旧系统的。于是，我们就力所能及的做一些重构和优化的工作好了。<img src="/images/smiles/icon_lol.gif"/><br /><br />现在的问题是，最近一段时间，公司的业务逻辑变化得有点快，有位老大提议是否能慢慢的把系统中的业务逻辑放入到SP中。他喜欢的方式是——程序只做基本的处理，相关的业务都直接通过调用SP或者FUNC来做。这样比较灵活。不过我的想法是，数据库应该只是一个做持久化的地方，如果和持久化关系不是很紧密的话，逻辑还是放入程序中好了。当然，这样做的后果是，有可能因为业务变化了，需要频繁的修改代码……<br /><br />我想，最理想的情况是，把逻辑都放入专门的逻辑规则引擎中（如iLog）之类的，不过，在目前暂没考虑规则引擎的情况下，是不是将逻辑封入SP就是比较完美的办法了呢？<br /><br />想请教下大家的看法呢？<img src="/images/smiles/icon_biggrin.gif"/>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234245" style="color:red;">已有 <strong>7</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Fri, 29 Aug 2008 09:04:51 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234245</link>
        <guid>http://www.javaeye.com/topic/234245</guid>
      </item>
      <item>
        <title>遇到Out Memory的几种情况总结</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://julycn.javaeye.com">julycn</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234540" style="color:red;">http://www.javaeye.com/topic/234540</a>&nbsp;
          发表时间: 2008年08月29日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>1、java设置内存的参数是否合适<br />2、查询数据库，遇到比较大的数据集，或者sql写的效率比较低<br />3、java处理文件的时候，如果文件比较大。</p>
<p>&nbsp;</p>
<p>我只想到这3中情况，系统那位能够继续补充。</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;">想要更多的人帮助你，请先帮助更多的人～～～</span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://datamining.group.javaeye.com/topic/234540" style="color:red;">已有 <strong>0</strong> 人发表回复，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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>Fri, 29 Aug 2008 17:27:17 +0800</pubDate>
        <link>http://www.javaeye.com/topic/234540</link>
        <guid>http://www.javaeye.com/topic/234540</guid>
      </item>
      <item>
        <title>ActiveMQ5.0实战三:使用Spring发送,消费topic和queue消息</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://andyao.javaeye.com">andyao</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/234101" style="color:red;">http://www.javaeye.com/topic/234101</a>&nbsp;
          发表时间: 2008年08月28日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <address><a href="http://www.javaeye.com/topic/153171">ActiveMQ5.0实战一: 安装配置ActiveMQ5.0</a>
</address>
<address><a href="http://www.javaeye.com/topic/154092">ActiveMQ5.0实战二: 基本配置</a>
</address>
<h3>简介</h3>
<p>实战一
, 实战二
介绍了ActiveMQ的基本概念和配置方式.</p>
<p>本篇将通过一个实例介绍使用spring发送,消费topic, queue类型消息的方法. 不懂topic和queue的google 之.</p>
<p>&nbsp;</p>
<p><a href="../../../upload/picture/pic/20785/485ba4ca-70db-3a46-a5c8-1cd3d9b81f65.gif" target="_blank"><img src="../../../upload/picture/pic/20785/485ba4ca-70db-3a46-a5c8-1cd3d9b81f65.gif" height="209" alt="" width="387" />
</a>
</p>
<p>如图示, TOPIC和QUEUE分别代表一个topic和一个queue消息通道. </p>
<ol>
<li>TopicMessageProducer向topic发送消息, TopicConsumerA和TopicConsumerB则从topic消费消息.</li>
<li>QueueMessageProducer向Queue发送消息, QueueConsumer从Queue中消费消息</li>
</ol>
<h3>Spring整合JMS</h3>
<p>就像对orm, web的支持一样, spring同样支持jms, 为整合jms到已有的项目提供了很多便利的方法. 本篇主要讲实战, 是所以先从配置开始, spring配置jms基本上需要8个部分.</p>
<ol>
<li>ConnectionFactory. 和jms服务器的连接, 可以是外部的jms server, 也可以使用embedded ActiveMQ Broker.</li>
<li>Destination. 有topic和queue两种方式.</li>
<li>JmsTemplate. spring提供的jms模板.</li>
<li>MessageConverter. 消息转换器.</li>
<li>MessageProducer. 消息生产者.</li>
<li>MessageConsumer. 消息消费者.</li>
<li>MessageListener. 消息监听器</li>
<li>MessageListenerContainer. 消息监听容器</li>
</ol>
<p>下面以实例的方式介绍上面8个部分.</p>
<h4>1. ConnectionFactory</h4>
<pre name="code" class="xml">&lt;amq:connectionFactory id=&quot;jmsConnectionFactory&quot; brokerURL=&quot;vm://localhost&quot; /&gt;</pre>
<p>&nbsp;brokerURL是指要连接的activeMQ server的地址, activeMQ提供了多种brokerURL, 集体可参见文档.一般我们使用嵌套的ActiveMQ server. 配置如下, 这个配置使用消息的存储机制, 服务器重启也不会丢失消息.</p>
<pre name="code" class="xml">&lt;!--  embedded ActiveMQ Broker --&gt;
	&lt;amq:broker useJmx=&quot;false&quot; persistent=&quot;true&quot;&gt;
		&lt;amq:persistenceAdapter&gt;
			&lt;amq:amqPersistenceAdapter directory=&quot;d:/amq&quot;/&gt;
		&lt;/amq:persistenceAdapter&gt;
		&lt;amq:transportConnectors&gt;
			&lt;amq:transportConnector uri=&quot;tcp://localhost:0&quot; /&gt;
		&lt;/amq:transportConnectors&gt;
	&lt;/amq:broker&gt;</pre>
<h4>&nbsp;2. Destination</h4>
<p>&nbsp;在实例中我们使用了两种destination</p>
<pre name="code" class="xml">&lt;!--  ActiveMQ destinations  --&gt;
&lt;!--  使用topic方式--&gt;
&lt;amq:topic name=&quot;TOPIC&quot; physicalName=&quot;JMS-TEST-TOPIC&quot; /&gt;
&lt;!--  使用Queue方式--&gt;
&lt;amq:queue name=&quot;QUEUE&quot; physicalName=&quot;JMS-TEST-QUEUE&quot; /&gt;</pre>
<h4>&nbsp;3. JmsTemplate</h4>
<pre name="code" class="xml">&lt;!--  Spring JmsTemplate config --&gt;
	&lt;bean id=&quot;jmsTemplate&quot; class=&quot;org.springframework.jms.core.JmsTemplate&quot;&gt;
		&lt;property name=&quot;connectionFactory&quot;&gt;
			&lt;!--  lets wrap in a pool to avoid creating a connection per send --&gt;
			&lt;bean class=&quot;org.springframework.jms.connection.SingleConnectionFactory&quot;&gt;
				&lt;property name=&quot;targetConnectionFactory&quot; ref=&quot;jmsConnectionFactory&quot; /&gt;
			&lt;/bean&gt;
		&lt;/property&gt;
		&lt;!-- custom MessageConverter --&gt;
		&lt;property name=&quot;messageConverter&quot; ref=&quot;defaultMessageConverter&quot; /&gt;
	&lt;/bean&gt;</pre>
<h4>
&nbsp;
4. MessageConverter</h4>
<p>&nbsp;&nbsp; MessageConverter实现的是org.springframework.jms.support.converter.MessageConverter接口, 提供消息的转换功能. DefaultMessageConverter的实现见附件.</p>
<pre name="code" class="xml">&lt;bean id=&quot;defaultMessageConverter&quot; class=&quot;com.andyao.activemq.DefaultMessageConverter&quot; /&gt;</pre>
<h4>&nbsp; 5. MessageProducer</h4>
<p>&nbsp;&nbsp; 实例拥有两个消息生产者, 消息生产者都是POJO, 实现见附件.</p>
<pre name="code" class="xml">&lt;!-- POJO which send Message uses  Spring JmsTemplate --&gt;
	&lt;bean id=&quot;topicMessageProducer&quot; class=&quot;com.andyao.activemq.TopicMessageProducer&quot;&gt;
		&lt;property name=&quot;template&quot; ref=&quot;jmsTemplate&quot; /&gt;
		&lt;property name=&quot;destination&quot; ref=&quot;TOPIC&quot; /&gt;
	&lt;/bean&gt;
	&lt;bean id=&quot;queueMessageProducer&quot; class=&quot;com.andyao.activemq.QueuMessageProducer&quot;&gt;
		&lt;property name=&quot;template&quot; ref=&quot;jmsTemplate&quot; /&gt;
		&lt;property name=&quot;destination&quot; ref=&quot;QUEUE&quot; /&gt;
	&lt;/bean&gt;</pre>
<h4>&nbsp;6. MessageConsumer</h4>
<p>&nbsp;TOPIC通道有两个消息消费者, QUEUE有一个消息消费者</p>
<pre name="code" class="xml">&lt;!--  Message Driven POJO (MDP) --&gt;
    &lt;!-- consumer1 for topic a --&gt;
    &lt;bean id=&quot;topicConsumerA&quot; class=&quot;com.andyao.activemq.TopicConsumerA&quot; /&gt;
    &lt;!-- consumer2 for topic a --&gt;
    &lt;bean id=&quot;topicConsumerB&quot; class=&quot;com.andyao.activemq.TopicConsumerB&quot; /&gt;
    &lt;!-- consumer for queue --&gt;
    &lt;bean id=&quot;queueConsumer&quot; class=&quot;com.andyao.activemq.QueueConsumer&quot; /&gt;</pre>
<h4>
&nbsp;
7. MessageListener</h4>
<p>每一个消息消费者都对应一个MessageListener</p>
<pre name="code" class="xml">&lt;bean id=&quot;topicListenerA&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;
		&lt;constructor-arg ref=&quot;topicConsumerA&quot; /&gt;
		&lt;!--  may be other method --&gt;
		&lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receive&quot; /&gt;
		&lt;!-- custom MessageConverter define --&gt;
		&lt;property name=&quot;messageConverter&quot; ref=&quot;defaultMessageConverter&quot; /&gt;
	&lt;/bean&gt;

	&lt;bean id=&quot;topicListenerB&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;
		&lt;constructor-arg ref=&quot;topicConsumerB&quot; /&gt;
		&lt;!--  may be other method --&gt;
		&lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receive&quot; /&gt;
		&lt;!-- custom MessageConverter define --&gt;
		&lt;property name=&quot;messageConverter&quot; ref=&quot;defaultMessageConverter&quot; /&gt;
	&lt;/bean&gt;

    &lt;bean id=&quot;queueListener&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;
		&lt;constructor-arg ref=&quot;queueConsumer&quot; /&gt;
		&lt;!--  may be other method --&gt;
		&lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receive&quot; /&gt;
		&lt;!-- custom MessageConverter define --&gt;
		&lt;property name=&quot;messageConverter&quot; ref=&quot;defaultMessageConverter&quot; /&gt;
	&lt;/bean&gt;</pre>
<h4>&nbsp;8. MessageListenerContainer</h4>
<p>&nbsp;有几个MessageListener既有几个MessageListenerContainer</p>
<pre name="code" class="xml">&lt;bean id=&quot;topicListenerContainerA&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
		&lt;property name=&quot;connectionFactory&quot; ref=&quot;jmsConnectionFactory&quot; /&gt;
		&lt;property name=&quot;destination&quot; ref=&quot;TOPIC&quot; /&gt;
		&lt;property name=&quot;messageListener&quot; ref=&quot;topicListenerA&quot; /&gt;
	&lt;/bean&gt;

    &lt;bean id=&quot;topicListenerContainerB&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
		&lt;property name=&quot;connectionFactory&quot; ref=&quot;jmsConnectionFactory&quot; /&gt;
		&lt;property name=&quot;destination&quot; ref=&quot;TOPIC&quot; /&gt;
		&lt;property name=&quot;messageListener&quot; ref=&quot;topicListenerB&quot; /&gt;
	&lt;/bean&gt;
    
    &lt;bean id=&quot;queueListenerContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
		&lt;property name=&quot;connectionFactory&quot; ref=&quot;jmsConnectionFactory&quot; /&gt;
		&lt;property name=&quot;destination&quot; ref=&quot;QUEUE&quot; /&gt;
		&lt;property name=&quot;messageListener&quot; ref=&quot;queu