﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Martin's Home-文章分类-Spring</title><link>http://www.blogjava.net/martinyuan/category/39729.html</link><description>希望我的积累对大家有所帮助！</description><language>zh-cn</language><lastBuildDate>Thu, 21 May 2009 07:53:26 GMT</lastBuildDate><pubDate>Thu, 21 May 2009 07:53:26 GMT</pubDate><ttl>60</ttl><item><title>利用Spring的AOP来配置和管理你的二级缓存(EHCache)</title><link>http://www.blogjava.net/martinyuan/articles/271946.html</link><dc:creator>Martin Yuan</dc:creator><author>Martin Yuan</author><pubDate>Thu, 21 May 2009 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/martinyuan/articles/271946.html</guid><wfw:comment>http://www.blogjava.net/martinyuan/comments/271946.html</wfw:comment><comments>http://www.blogjava.net/martinyuan/articles/271946.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/martinyuan/comments/commentRss/271946.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/martinyuan/services/trackbacks/271946.html</trackback:ping><description><![CDATA[
		<div align="center">
				<strong>
						<font size="4">利用Spring的AOP来配置和管理你的二级缓存(EHCache)</font>
				</strong>
		</div>
		<div align="left">
				<font size="3">       如果我们的项目中采用的是Spring+hibernate来构建的，在缓存方面，我们一定会首先想到Spring自带的EHCache缓存工具，在Spring中集成了目前比较流行的缓存策略EHCache，现在用的比较多的还有像OSCache,MemCached.这些应该是当前用的最多的缓存工具了。</font>
		</div>
		<div align="left">
				<font size="3">       在Spring+hibernate的这样的框架中，EHCache应该属于二级缓存了，我们知道在Hibernate中已经默认的使用了一级缓存，也就是在Session中。二级缓存应该是SessionFactory的范围了。二级缓存默认不会起作用的，这就需要我们简单的配置一下就可以了。</font>
		</div>
		<div align="left">
				<font size="3">       在配置之前，我先说明一点，缓存从理论上来说是可以提高你网站系统的性能，但前提就是你要保证你有一个良好的架构设计。比如用Spring+Hibernate构建的系统，如果用单个服务器，用Spring自带的EHCache来做二级缓存是再好不过了。如果你的系统是分布式的系统，有多台服务器，那么MemCached是最好的选择了，一般来说MemCached在做缓存这一块，要比EHCache和OSCache的性能要好点，但是并不是所有的网站用MemCached都能达到事半功倍的，它虽然是比较好，但它有一个前提，那就是你有多台服务器，是分布式的。这样用MemCached对系统的性能一定OK。因为Memcached是“分布式”的内存对象缓存系统，那么就是说，那些不需要“分布”的，不需要共享的，或者干脆规模小到只有一台服务器的应用， MemCached不会带来任何好处，相反还会拖慢系统效率，因为网络连接同样需要资源</font>
				<font size="3"> .OSCache这个缓存机制的限制就比较少了。它和EHCache差不多。</font>
		</div>
		<div align="left">
				<font size="3">        在Spring+Hibernate中整合EHCache只需简单的三步。</font>
		</div>
		<div align="left">
				<font size="3">        第一步：配置缓存文件ehcache.xml，默认放到src目录下。下面是简单的配置。</font>
		</div>
		<div align="left">
				<font size="3">   &lt;ehcache&gt;<br />    &lt;!—设置缓存文件 .data 的创建路径。</font>
		</div>
		<div align="left">
				<font size="3">         如果该路径是 Java 系统参数，当前虚拟机会重新赋值。</font>
		</div>
		<div align="left">
				<font size="3">         下面的参数这样解释：<br />         user.home – 用户主目录<br />         user.dir      – 用户当前工作目录<br />         java.io.tmpdir – 默认临时文件路径，就是在tomcat的temp目录 --&gt;<br />    &lt;diskStore path="java.io.tmpdir"/&gt;</font>
		</div>
		<div align="left">
				<font size="3">
						<br />    &lt;!—缺省缓存配置。CacheManager 会把这些配置应用到程序中。</font>
		</div>
		<div align="left">        下列属性是 defaultCache 必须的：</div>
		<div align="left">        maxInMemory           - 设定内存中创建对象的最大值。<br />        eternal                        - 设置元素（译注：内存中对象）是否永久驻留。如果是，将忽略超<br />                                              时限制且元素永不消亡。<br />        timeToIdleSeconds  - 设置某个元素消亡前的停顿时间。<br />                                              也就是在一个元素消亡之前，两次访问时间的最大时间间隔值。<br />                                              这只能在元素不是永久驻留时有效（译注：如果对象永恒不灭，则<br />                                              设置该属性也无用）。<br />                                              如果该值是 0 就意味着元素可以停顿无穷长的时间。<br />        timeToLiveSeconds - 为元素设置消亡前的生存时间。<br />                                               也就是一个元素从构建到消亡的最大时间间隔值。<br />                                               这只能在元素不是永久驻留时有效。<br />        overflowToDisk        - 设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘<br />                                               上。<br />        --&gt;<br />     &lt;!--timeToLiveSeconds的时间一定要大于等于timeToIdleSeconds的时间按--&gt;<br />    &lt;cache name="DEFAULT_CACHE"<br />        maxElementsInMemory="1000"<br />        eternal="false"<br />        timeToIdleSeconds="500"<br />        timeToLiveSeconds="500"<br />        overflowToDisk="true"<br />        /&gt;<br />&lt;/ehcache&gt;</div>
		<div align="left">  上面有一个默认的缓存配置，还有一个我们自己配置的缓存，在应用程序中如果不指明缓存的话，就会默认的使用默认的配置属性。</div>
		<div align="left">    第二步：用Spring中的强大机制，面向切面的设计AOP.来编写两个类文件，MethodCacheAfterAdvice.java(主要是对脏东西的同步更新)和MethodCacheInterceptor.java（主要使用拦截器来为要缓存的对象建立缓存并缓存）。拦截器的实现机制其实就是我们常用的过滤器。它和过滤器的工作原理一样。以下是这两个文件。</div>
		<div align="left">
				<strong>MethodCacheInterceptor.java</strong>
		</div>
		<div align="left"> public class MethodCacheInterceptor implements MethodInterceptor,<br />  InitializingBean {<br /> private static final Log logger = LogFactory<br />   .getLog(MethodCacheInterceptor.class);</div>
		<div align="left"> private Cache cache;</div>
		<div align="left"> public void setCache(Cache cache) {<br />  this.cache = cache;<br /> }</div>
		<div align="left"> public MethodCacheInterceptor() {<br />  super();<br /> }</div>
		<div align="left">
				<br /> public Object invoke(MethodInvocation invocation) throws Throwable {<br />  String targetName = invocation.getThis().getClass().getName();<br />  String methodName = invocation.getMethod().getName();<br />  Object[] arguments = invocation.getArguments();<br />  Object result;<br />  logger.debug("Find object from cache is " + cache.getName());<br />  String cacheKey = getCacheKey(targetName, methodName, arguments);<br />  Element element = cache.get(cacheKey);<br />  long startTime = System.currentTimeMillis();<br />  if (element == null) {<br />   logger<br />     .debug("Hold up method , Get method result and create cache........!");<br />   result = invocation.proceed();<br />   element = new Element(cacheKey, (Serializable) result);<br />   cache.put(element);<br />   long endTime = System.currentTimeMillis();<br />   logger.info(targetName + "." + methodName + " 方法被首次调用并被缓存。耗时"<br />     + (endTime - startTime) + "毫秒" + " cacheKey:"<br />     + element.getKey());<br />  } else {<br />   long endTime = System.currentTimeMillis();<br />   logger.info(targetName + "." + methodName + " 结果从缓存中直接调用。耗时"<br />     + (endTime - startTime) + "毫秒" + " cacheKey:"<br />     + element.getKey());<br />  }<br />  return element.getValue();<br /> }</div>
		<div align="left">
				<br /> private String getCacheKey(String targetName, String methodName,<br />   Object[] arguments) {<br />  StringBuffer sb = new StringBuffer();<br />  sb.append(targetName).append(".").append(methodName);<br />  if ((arguments != null) &amp;&amp; (arguments.length != 0)) {<br />   for (int i = 0; i &lt; arguments.length; i++) {<br />    sb.append(".").append(arguments[i]);<br />   }<br />  }<br />  return sb.toString();<br /> }</div>
		<div align="left">
				<br /> public void afterPropertiesSet() throws Exception {<br />  Assert.notNull(cache,<br />    "Need a cache. Please use setCache(Cache) create it.");<br /> }</div>
		<div align="left">}</div>
		<div align="left">   这个方法实现了两个接口，一个是MethodInterceptor（方法拦截），它主要是在方法的调用前后都可以执行。另一个InitializingBean （初始化Bean）它主要在方法调用之后做一下简单的检查，主要实现写在afterPropertiesSet()中，就可以了。</div>
		<div align="left">
				<strong>MethodCacheAfterAdvice</strong>
				<strong>.java</strong>
				<br />public class MethodCacheAfterAdvice implements AfterReturningAdvice,<br />  InitializingBean {<br /> private static final Log logger = LogFactory<br />   .getLog(MethodCacheAfterAdvice.class);</div>
		<div align="left"> private Cache cache;</div>
		<div align="left"> public void setCache(Cache cache) {<br />  this.cache = cache;<br /> }</div>
		<div align="left"> public MethodCacheAfterAdvice() {<br />  super();<br /> }</div>
		<div align="left"> public void afterReturning(Object arg0, Method arg1, Object[] arg2,<br />   Object arg3) throws Throwable {<br />  String className = arg3.getClass().getName();<br />  List list = cache.getKeys();<br />  for (int i = 0; i &lt; list.size(); i++) {<br />   String cacheKey = String.valueOf(list.get(i));<br />   if (cacheKey.startsWith(className)) {<br />    cache.remove(cacheKey);<br />    logger.debug("remove cache " + cacheKey);<br />   }<br />  }<br /> }</div>
		<div align="left"> public void afterPropertiesSet() throws Exception {<br />  Assert.notNull(cache,<br />    "Need a cache. Please use setCache(Cache) create it.");<br /> }<br />}<br />  这个方法主要是保证缓存的同步，保持与数据库的数据一致性。<br />第三步：配置Bean了，applicationContext-ehcache.xml文件就是Spring中的Ioc（控制反转容器）的描述了。上面的只是简单的写了两个方法，具体的能起到什么作用，以及何时起作用，以及怎样用声明式的方式(AOP)和Bean结合。</div>
		<div align="left">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;beans xmlns="<a href="http://www.springframework.org/schema/beans">[url]http://www.springframework.org/schema/beans[/url]</a>"<br /> xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">[url]http://www.w3.org/2001/XMLSchema-instance[/url]</a>"<br /> xsi:schemaLocation="<a href="http://www.springframework.org/schema/beans">[url]http://www.springframework.org/schema/beans[/url]</a><a href="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">[url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]</a>"&gt;</div>
		<div align="left"> &lt;!-- 利用BeanNameAutoProxyCreator自动创建事务代理 --&gt;<br /> &lt;bean id="transactionInterceptor"<br />  class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt;<br />  &lt;property name="transactionManager"&gt;<br />   &lt;ref bean="transactionManager" /&gt;<br />  &lt;/property&gt;<br />  &lt;!-- 配置事务属性 --&gt;<br />  &lt;property name="transactionAttributes"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="delete*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="find*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />    &lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;!-- 引用ehCache的配置 --&gt;<br /> &lt;bean id="defaultCacheManager"<br />  class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;<br />  &lt;property name="configLocation"&gt;<br />   &lt;value&gt;classpath:ehcache.xml&lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</div>
		<div align="left"> &lt;!-- 定义ehCache的工厂，并设置所使用的Cache name --&gt;<br /> &lt;bean id="ehCache"<br />  class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />  &lt;property name="cacheManager"&gt;<br />   &lt;ref local="defaultCacheManager" /&gt;<br />  &lt;/property&gt;<br />  &lt;property name="cacheName"&gt;<br />   &lt;value&gt;DEFAULT_CACHE&lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</div>
		<div align="left"> &lt;!-- find/create cache拦截器 --&gt;<br /> &lt;bean id="methodCacheInterceptor"<br />  class="com.w3cs.cache.ehcache.MethodCacheInterceptor"&gt;<br />  &lt;property name="cache"&gt;<br />   &lt;ref local="ehCache" /&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> &lt;!-- flush cache拦截器 --&gt;<br /> &lt;bean id="methodCacheAfterAdvice"<br />  class="com.w3cs.cache.ehcache.MethodCacheAfterAdvice"&gt;<br />  &lt;property name="cache"&gt;<br />   &lt;ref local="ehCache" /&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</div>
		<div align="left"> &lt;bean id="methodCachePointCut"<br />  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;<br />  &lt;property name="advice"&gt;<br />   &lt;ref local="methodCacheInterceptor" /&gt;<br />  &lt;/property&gt;<br />  &lt;property name="patterns"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;.*find.*&lt;/value&gt;<br />    &lt;value&gt;.*get.*&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> &lt;bean id="methodCachePointCutAdvice"<br />  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;<br />  &lt;property name="advice"&gt;<br />   &lt;ref local="methodCacheAfterAdvice" /&gt;<br />  &lt;/property&gt;<br />  &lt;property name="patterns"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;.*create.*&lt;/value&gt;<br />    &lt;value&gt;.*update.*&lt;/value&gt;<br />    &lt;value&gt;.*delete.*&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</div>
		<div align="left"> &lt;!-- 自动代理 --&gt;<br /> &lt;bean id="autoproxy"<br />  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;<br />  &lt;!-- 可以是Service或DAO层（最好是针对业务层*Service） --&gt;<br />  &lt;property name="beanNames"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;*DAO&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br />  &lt;property name="interceptorNames"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;methodCachePointCut&lt;/value&gt;<br />    &lt;value&gt;methodCachePointCutAdvice&lt;/value&gt;<br />    &lt;value&gt;transactionInterceptor&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br />&lt;/beans&gt;</div>
		<div align="left">
				<font size="3">        上面我是针对DAO层进行拦截并缓存的，最好是能在业务层进行拦截会更好，你可以根据你的系统具体的设计，如果没有业务层的话，对DAO层拦截也是可以的。拦截采用的是用正规表达式配置的。对find,get的方法只进行缓存，如果 create，update,delete方法进行缓存的同步。对一些频繁的操作最好不要用缓存，缓存的作用就是针对那些不经常变动的操作。</font>
		</div>
		<div align="left">
				<font size="3">         只需这简单的三部就可以完成EHCache了。最好亲自试一试。我并没有针对里面对方法过细的讲解。其实都很简单，多看看就会明白了。不当之处，敬请原谅。</font>
		</div>
<img src ="http://www.blogjava.net/martinyuan/aggbug/271946.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/martinyuan/" target="_blank">Martin Yuan</a> 2009-05-21 13:49 <a href="http://www.blogjava.net/martinyuan/articles/271946.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用BeanNameAutoProxyCreator实现spring的自动代理</title><link>http://www.blogjava.net/martinyuan/articles/271949.html</link><dc:creator>Martin Yuan</dc:creator><author>Martin Yuan</author><pubDate>Thu, 21 May 2009 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/martinyuan/articles/271949.html</guid><wfw:comment>http://www.blogjava.net/martinyuan/comments/271949.html</wfw:comment><comments>http://www.blogjava.net/martinyuan/articles/271949.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/martinyuan/comments/commentRss/271949.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/martinyuan/services/trackbacks/271949.html</trackback:ping><description><![CDATA[
		<p>提到代理，我们可以使用ProxyBeanFactory，并配置proxyInterfaces,target和interceptorNames实现，但如果需要代理的bean很多，无疑会对spring配置文件的编写带来繁重的工作</p>
		<p>
				<br />Spring为我们提供了，根据beanName匹配后进行自动代理的解决方法</p>
		<p>业务接口</p>
		<p> </p>
		<p>package AutoProxyOne;</p>
		<p>public interface Shopping ...{<br />  public String buySomething(String type);<br />  public String buyAnything(String type);<br />  public String sellSomething(String type);<br />  public String sellAnything(String type);</p>
		<p>
				<br />}</p>
		<p> 业务实现类A，作为配置文件中的buyBean：</p>
		<p> </p>
		<p>package AutoProxyOne;</p>
		<p>public class ShoppingImplA implements Shopping ...{<br />    private Customer customer;<br />    public Customer getCustomer() ...{<br />        return customer;<br />    }<br />    public void setCustomer(Customer customer) ...{<br />        this.customer = customer;<br />    }<br />    public String buySomething(String type) ...{<br />        System.out.println(this.getCustomer().getName()+" bye "+type+" success");<br />        return null;<br />    }<br />   <br />    public String buyAnything(String type) ...{<br />       System.out.println(this.getCustomer().getName()+" bye "+type+" success");<br />       return null;</p>
		<p>     }<br />    public String sellAnything(String type) ...{<br />        System.out.println(this.getCustomer().getName()+" sell "+type+" success");<br />        return null;<br />    }<br />    public String sellSomething(String type) ...{<br />         System.out.println(this.getCustomer().getName()+" sell "+type+" success");<br />           return null;<br />    }</p>
		<p>}</p>
		<p> </p>
		<p> 业务实现类B，作为配置文件中的sellBean：</p>
		<p> </p>
		<p>package AutoProxyOne;</p>
		<p>public class ShoppingImplB implements Shopping ...{<br />    private Customer customer;<br />    public Customer getCustomer() ...{<br />        return customer;<br />    }<br />    public void setCustomer(Customer customer) ...{<br />        this.customer = customer;<br />    }<br />    public String buySomething(String type) ...{<br />        System.out.println(this.getCustomer().getName()+" bye "+type+" success");<br />        return null;<br />    }<br />   <br />    public String buyAnything(String type) ...{<br />       System.out.println(this.getCustomer().getName()+" bye "+type+" success");<br />       return null;</p>
		<p>     }<br />    public String sellAnything(String type) ...{<br />        System.out.println(this.getCustomer().getName()+" sell "+type+" success");<br />        return null;<br />    }<br />    public String sellSomething(String type) ...{<br />         System.out.println(this.getCustomer().getName()+" sell "+type+" success");<br />           return null;<br />    }</p>
		<p>}</p>
		<p> </p>
		<p>切面通知：</p>
		<p> </p>
		<p>package AutoProxyOne;</p>
		<p>import java.lang.reflect.Method;</p>
		<p>import org.springframework.aop.MethodBeforeAdvice;<br />//前置通知<br />public class WelcomeAdvice implements MethodBeforeAdvice ...{</p>
		<p>    public void before(Method method, Object[] args, Object obj)<br />            throws Throwable ...{<br />       <br />        System.out.println("Hello welcome to bye ");</p>
		<p>    }</p>
		<p>}</p>
		<p> </p>
		<p>配置文件：</p>
		<p>其中beanNames为buy*,意味着所有以buy开头的bean,都被spring容易自动代理，执行相应的切面通知</p>
		<p> </p>
		<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "<a href="http://www.springframework.org/dtd/spring-beans.dtd">http://www.springframework.org/dtd/spring-beans.dtd</a>" &gt;<br />&lt;beans&gt;<br /> &lt;bean id="WelcomeAdvice" class="AutoProxyOne.WelcomeAdvice"&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;bean  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;<br />   &lt;property name="beanNames"&gt;<br />     &lt;list&gt;<br />       &lt;value&gt;buy*&lt;/value&gt;<br />     &lt;/list&gt;<br />   &lt;/property&gt;<br />   &lt;property name="interceptorNames"&gt;<br />     &lt;list&gt;<br />        &lt;value&gt;WelcomeAdvice&lt;/value&gt;<br />     &lt;/list&gt;<br />   &lt;/property&gt;</p>
		<p> &lt;/bean&gt;<br />  <br />  &lt;bean id="buyBean" class="AutoProxyOne.ShoppingImplA"&gt;<br />    &lt;property name="customer"&gt;<br />      &lt;ref bean="customer"/&gt;<br />    &lt;/property&gt;<br />   &lt;/bean&gt;<br /> &lt;bean id="sellBean" class="AutoProxyOne.ShoppingImplB"&gt;<br />    &lt;property name="customer"&gt;<br />      &lt;ref bean="customer"/&gt;<br />    &lt;/property&gt;<br />   &lt;/bean&gt;</p>
		<p>
				<br />&lt;bean id="customer" class="AutoProxyOne.Customer"&gt;<br />   &lt;constructor-arg index="0"&gt;<br />     &lt;value&gt;gaoxiang&lt;/value&gt;<br />   &lt;/constructor-arg&gt;<br />    &lt;constructor-arg index="1"&gt;<br />     &lt;value&gt;26&lt;/value&gt;<br />   &lt;/constructor-arg&gt;<br /> &lt;/bean&gt;</p>
		<p>
				<br />&lt;/beans&gt;</p>
		<p>
				<br /> </p>
		<p>测试代码：</p>
		<p>在测试代码中，我们的buyBean打印两条买的信息，sellBean打印两条卖的信息，可以看到buyBean执行的方法已经进行了切面处理</p>
		<p>需要注意的是，如果使用自动代码，则获得Spring Bean工厂要用</p>
		<p>ApplicationContext ctx=new FileSystemXmlApplicationContext(filePath);</p>
		<p>而不能用</p>
		<p>BeanFactory factory=new XmlBeanFactory(new FileSystemResource(filePath));</p>
		<p>原因我想是因为BeanFactory在初始化时并不实例化单例的Bean,而ApplicationContext则在初始化时候全部实例化了Bean,自动代理需要在初始化时候定义好代理关系</p>
		<p> </p>
		<p>package AutoProxyOne;</p>
		<p>import java.io.File;</p>
		<p>import org.springframework.beans.factory.BeanFactory;<br />import org.springframework.beans.factory.xml.XmlBeanFactory;<br />import org.springframework.context.ApplicationContext;<br />import org.springframework.context.support.FileSystemXmlApplicationContext;<br />import org.springframework.core.io.FileSystemResource;</p>
		<p>
				<br />import org.springframework.aop.support.RegexpMethodPointcutAdvisor;<br />public class TestAdvisor ...{</p>
		<p>    public static void main(String[] args) ...{</p>
		<p>        String filePath=System.getProperty("user.dir")+File.separator+"AutoProxyOne"+File.separator+"hello.xml";<br />       <br />        BeanFactory factory=new XmlBeanFactory(new FileSystemResource(filePath));<br />        ApplicationContext ctx=new FileSystemXmlA</p>
<img src ="http://www.blogjava.net/martinyuan/aggbug/271949.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/martinyuan/" target="_blank">Martin Yuan</a> 2009-05-21 13:49 <a href="http://www.blogjava.net/martinyuan/articles/271949.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SiteMesh介绍 (转)</title><link>http://www.blogjava.net/martinyuan/articles/271937.html</link><dc:creator>Martin Yuan</dc:creator><author>Martin Yuan</author><pubDate>Thu, 10 Jan 2008 08:16:00 GMT</pubDate><guid>http://www.blogjava.net/martinyuan/articles/271937.html</guid><wfw:comment>http://www.blogjava.net/martinyuan/comments/271937.html</wfw:comment><comments>http://www.blogjava.net/martinyuan/articles/271937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/martinyuan/comments/commentRss/271937.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/martinyuan/services/trackbacks/271937.html</trackback:ping><description><![CDATA[
		<p>作者：by <a href="http://today.java.net/pub/au/13">Will Iverson</a> 03/11/2004<br />汉化：by <a href="mailto:andnet@gmail.com">AndNeT</a> 03/24/2005</p>
		<p>注：sitemesh，一个不错的tiles替代方案，比tiles做的更漂亮优雅。本文是sitemesh官方推荐的入门文档，本来想自己翻译的，突然发现有人先行一步了，就转过来看吧。</p>
		<p>
				<br />以前我通常使用旧式的方法来建立自己的web应用：手工排版，仔细使用每一个字节使其工作在Unicode下，同时使用make文件来适应不同的CPU……</p>
		<p>或许现在我们可以换一种方式。</p>
		<p>尽管我从没有感觉到需要使用assembly (CISC or RISC)来建立web应用，但也会偶尔觉得我的开发伙伴的工作相当繁琐。特别是我发现很多的开发者在痛苦的寻求一种比较好的方式来控制web应用的基本 模块：例如那些页头、页尾、导航栏、打印页面、手持设备的轻量级页面，以及其他更多的问题。到了最后，令人惊异的是大部分人都采用了落后的 includes和复制粘贴方式。</p>
		<p>根据经验，我可以采用在<u><font color="#0000ff"> java.net </font></u>上开源的servlet 过滤器 <a href="http://www.opensymphony.com/sitemesh/">SiteMesh</a>n 来简单明了并优雅的解决这些问题。作为一种替代新的templating语言（XSLT）或部署您的页面到新的系统的解决方法，应用SiteMesh可以 相当容易处理你的页面，这一切只需要普通的HTML，JSP，servlet(包括Struts)，以及其他常用的技术。</p>
		<h2 id="How_Does_It_Work">工作原理</h2>
		<p>SiteMesh利用了一种很少人知道的servlet规范实现了一种页面过滤器。设想一下，现在有一个简单的jsp页面用来返回当前的日期和时 间。通常这个页面请求来到应用服务器，页面被处理，最后处理结果返回到web浏览器。SiteMesh作为一个页面过滤器，在页面被处理之后，返回web 浏览器之前，对页面做了一些附加的操作。这个变化简单描述为图一和图二所示的附加步骤。 </p>
		<p>
				<img style="WIDTH: 420px; CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig1.gif" width="520" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图一：普通页面处理情况</em>
		</p>
		<p>
				<img style="WIDTH: 420px; CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig2.gif" width="520" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图二：SiteMesh对页面处理情况</em>
		</p>
		<p>现在看一个简单的例子。</p>
		<pre>
				<code>&lt;html&gt;<br /> &lt;head&gt;<br /> &lt;title&gt;Simple Document&lt;/title&gt;<br /> &lt;/head&gt;<br /> &lt;body&gt;<br /> Hello World! &lt;br /&gt;<br /> &lt;%= 1+1 %&gt;<br /> &lt;/body&gt;<br />&lt;/html&gt;</code>
		</pre>
		<p>你会发现这个页面有一个title和body（类似普通的HTML页面）。你也会发现一小段JSP代码——它将会如同你期望的那样被处理。同时你可以使用任何你想使用的JSP语法和特性来替换这一小段代码。 </p>
		<p>现在来看一个简单的SiteMesh "装饰（decorator）"页面。列表2显示了一个被SiteMesh调用的JSP页面。</p>
		<pre>
				<code>&lt;%@ taglib uri="sitemesh-decorator"<br />prefix="decorator" %&gt;<br />&lt;html&gt;<br /> &lt;head&gt;<br /> &lt;title&gt;<br /> My Site - &lt;decorator:title default="Welcome!" /&gt;<br /> &lt;/title&gt;<br /> &lt;decorator:head /&gt;<br /> &lt;/head&gt;<br /> &lt;body&gt;<br /> &lt;h1&gt;&lt;decorator:title default="Welcome!" /&gt;&lt;/h1&gt;<br /> &lt;p&gt;&lt;decorator:body /&gt;&lt;/p&gt; <br /> &lt;p&gt;&lt;small&gt;<br /> (&lt;a <br /> href="http://www.zhmy.com/?printable=true"&gt;printable version&lt;/a&gt;<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://218.249.43.230/images/smileys/wink.gif" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" /><br /> &lt;/small&gt;&lt;/p&gt;<br /> &lt;/body&gt;<br />&lt;/html&gt;</code>
		</pre>
		<p>查看这个装饰器（decorator），我们能看到一些有趣的东西。首先，在第一行申明了一个SiteMesh标签库。这个标签库包含了与原始页面一起工作时所需的所有东西。你能看到我们使用了两个SiteMesh的装饰标签（declared tags）， <code><font face="新宋体">&lt;decorator:title&gt;</font></code> 和 <code><font face="新宋体">&lt;decorator:body&gt;</font></code> 。不要惊讶于标签<font face="Courier New">&lt;decorator:title&gt;在</font>原始页面中显示<font face="Courier New">&lt;title&gt;标签</font>中的内容， <code><font face="新宋体">&lt;decorator:body&gt;</font></code> 中的内容也是如此。我们在这个页面的HEAD和BODY元素都使用了同一个title标签。（We're making a few fairly radical changes to the page, including repeating the title both in the <code><font face="新宋体">HEAD</font></code> element as well as the <code><font face="新宋体">BODY</font></code>. ）同时，我们还增加了一个到可打印版本页面的链接。</p>
		<p>作为对照，图三显示了原始处理页面，图四显示了被修饰过的处理页面。留意被装饰页面在浏览器窗口显示的标题文字和HTML内容。同时也可以看到增加了一个可打印页面的链接——这个我们回头再说。 </p>
		<p>
				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig3.gif" width="309" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图三：原始未修饰页面</em>
		</p>
		<p>
				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig4.gif" width="309" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图四：被修饰页面</em>
		</p>
		<p>很明显，对比起使用include（例如<font face="Courier New">&lt;jsp:include page="foo.jsp" flush="true" /&gt;</font>）来说，以这样的方式使用页头、页尾系统结构要清晰得多。这种方式更易移植、更易理解，同时也鼓励了JSP页面不再使用导航或其他类似的表现层代码。我发现在JSP页面中使用装饰器和CSS的组合比标准HTML的标签更容易去除格式信息。</p>
		<h2 id="Installing_SiteMesh">安装SiteMesh</h2>
		<p>注意下面的屏幕截图是基于Windows XP Professional， <a href="http://jakarta.apache.org/tomcat/index.html">Tomcat 5.0.19</a>， 和Java 2 SDK 1.4.2_03的环境之上的。在这里我假定你的Tomcat已经安装完毕并且可以正常工作了。你或许会有一些混淆，但我们已经成功地在Tomcat 4.1 和 WebLogic 测试过，同时 SiteMesh 也支持大部分的web应用服务器。 </p>
		<p>本文描述的SiteMesh 2.0.1可以在 <a href="https://sitemesh.dev.java.net/servlets/ProjectDocumentList?folderID=542">下载</a>到。 在java.net 上SiteMesh's 的项目库中有四个文件可以下载。<em>sitemesh-2.0.1.jar</em> 是其核心 JAR 文件， <em>sitemesh-2.0.1-sources.zip</em> 的作用正如同其名字所述， <em>sitemesh-example.war</em> 则提供了一个复杂的例子用来显示一些SiteMesh的高级特性。</p>
		<p>为了使描述更加简单，我们从<a href="https://sitemesh.dev.java.net/files/documents/887/2097/sitemesh-example.war"><em>sitemesh-blank.war</em></a> 文件开始。将该WAR文件放入Tomcat 的<em>webapps</em> 目录，WAR包将自动解压显示内容（SoSo注：这里的前提是你的tomcat已经开始工作），如图五所示。</p>
		<p>
				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig5.gif" width="201" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图五： SiteMesh_blank.WAR解开后的内容</em>
		</p>
		<p>我们花点时间描述一下这些文件的作用。</p>
		<h5 id="web_xml">
				<em>web.xml</em>
		</h5>
		<p>首先，<em>WEB-INF/web.xml</em> 文件显示如列表3，这些语句用来安装SiteMesh 过滤器和标签库。如果你决定在一个已有的Web应用中使用SiteMesh，你必须把这些语句添加到你的<em>WEB-INF/web.xml</em> 文件中。</p>
		<pre>
				<code>&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br /> &lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" <br /> "http://java.sun.com/dtd/web-app_2_3.dtd"&gt; <br />&lt;web-app&gt; <br /> &lt;!-- Start of SiteMesh stuff --&gt; <br /> &lt;filter&gt;<br /> &lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br /> &lt;filter-class&gt;com.opensymphony.module.sitemesh.filter.PageFilter&lt;/filter-class&gt;<br /> &lt;/filter&gt; <br /> &lt;filter-mapping&gt;<br /> &lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br /> &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br /> &lt;/filter-mapping&gt; <br /> &lt;taglib&gt;<br /> &lt;taglib-uri&gt;sitemesh-page&lt;/taglib-uri&gt;<br /> &lt;taglib-location&gt;/WEB-INF/sitemesh-page.tld&lt;/taglib-location&gt;<br /> &lt;/taglib&gt; <br /> &lt;taglib&gt;<br /> &lt;taglib-uri&gt;sitemesh-decorator&lt;/taglib-uri&gt;<br /> &lt;taglib-location&gt;/WEB-INF/sitemesh-decorator.tld&lt;/taglib-location&gt;<br /> &lt;/taglib&gt; <br /> &lt;!-- End of SiteMesh stuff --&gt; <br />&lt;/web-app&gt;</code>
		</pre>
		<p>注意：这里需要注意一下<code><font face="新宋体">url-pattern</font></code>的写法-- 如果使用的是Tomcat 5（而不是 Tomcat 4 ），需要将默认的*修改如*.jsp的形式。最新的servlet规范不再支持*样式。</p>
		<h5 id="decorators_xml">
				<em>decorators.xml</em>
		</h5>
		<p>
				<em>WEB-INF/decorators.xml</em> 文件用来将一个装饰器名字同一个专门的JSP装饰文件绑定。作为一个例子，这里将JSP装饰文件minimal.jsp同一个称为handheld的装饰器绑定起来。</p>
		<pre>
				<code>&lt;decorators defaultdir="/decorators"&gt;<br /> &lt;decorator name="main" page="main.jsp"&gt;<br /> &lt;pattern&gt;*&lt;/pattern&gt;<br /> &lt;/decorator&gt;<br /><br /> &lt;decorator name="panel" page="panel.jsp"/&gt;<br /> &lt;decorator name="printable" page="printable.jsp"/&gt;<br />&lt;/decorators&gt;</code>
		</pre>
		<p>正如我们在代码列表里看到的一样，我们定义了三个装饰器，他们分别绑定了三个类似的JSP页面。我们可以看到一个默认装饰器（main.jsp），它将被默认运用于所有文件。</p>
		<p>缺省的，SiteMesh使用下面的逻辑来选择使用哪一个装饰器：</p>
		<!-- sidebar begins -->
		<table cellspacing="12" cellpadding="6" width="200" align="right" border="0">
				<tbody>
						<tr>
								<td valign="top" bgcolor="#efefef">
										<p>这个逻辑在<em>sitemesh-2.0.1.jar</em> 包的 <em>\com\opensymphony\module\sitemesh\factor\sitemesh-default.xml</em> 文件里被描述。你可以针对诸如：客户端操作系统，web浏览器，用户代理等在<em>WEB-INF\sitemesh.xml</em>文件里，通过一个变量覆盖这个行为。(You can override this behavior with a wide variety of <a href="http://www.opensymphony.com/sitemesh/api/com/opensymphony/module/sitemesh/mapper/package-summary.html">built-in mappers </a>for things like language, client operating system, web browser/user agent, etc. by creating a <em>WEB-INF\sitemesh.xml</em> file. ）可以在<em>sitemesh-example.war</em> 找到例子。</p>
								</td>
						</tr>
				</tbody>
		</table>
		<!-- sidebar ends -->
		<ol>
				<li>页面是否使用meta装饰器标签（meta decorator tag）特别指定了一个装饰器？ 
</li>
				<li>页面是否是一个框架集（是的话则不应用装饰器）？ 
</li>
				<li>页面是否使用了<code><font face="新宋体">printable=true</font></code> 参数（是的话则使用打印装饰器） 
</li>
				<li>页面时候使用装饰器文件名特别指定了一个装饰器？ 
</li>
				<li>页面是否匹配 <em>decorators.xml</em> 文件里描述的样式？ </li>
		</ol>
		<p>通常第一条规则仅用来确定该装饰器是否被使用（Conceptually, the first rule that evaluates to true determines the decorator that is used. ）在上面的例子中，当出现<code><font face="新宋体">printable=true</font></code> 参数的时候，装饰器<code><font face="新宋体">printable.jsp</font></code> （规则 #3）替代了 <code><font face="新宋体">main.jsp</font></code> （规则 #5）。在SiteMesh中，这些规则被描述为 <em>mappers。</em></p>
		<h5 id="decorators_jsp">
				<em>decorators/*.jsp</em>
		</h5>
		<p>这三个decorators目录下的文件是<em>decorators.xml</em>文件中描述的不同装饰器JSP文件。上面是一个简单的装饰器例子，在后面我们将讨论更复杂的示例。</p>
		<h5 id="sitemesh_jar">
				<em>sitemesh-2.0.1.jar</em>
		</h5>
		<p>这是SiteMesh最主要的二进制文件，通常被安装在 <em>WEB-INF/lib</em> 目录下。可以在<a href="http://www.opensymphony.com/sitemesh/api">www.opensymphony.com/sitemesh/api</a> 找到这个库的javadoc。</p>
		<h5 id="tld">
				<em>*.tld</em>
		</h5>
		<p>SiteMesh使用两个标签库，但大多数人都只需要<em>sitemesh-decorator.tld</em>。你可以在 <a href="http://www.opensymphony.com/sitemesh/tags.html">www.opensymphony.com/sitemesh/tags.html</a> 找到相应的文档。我们已经讲述了最主要的标签：head，title和body。在下一章我们来讨论剩下的标签：getProperty。 </p>
		<h2 id="Advanced_SiteMesh">SiteMesh高级特性</h2>
		<p>SiteMesh的一个重要特性是使用原始HTML的meta标签（例如<font face="Courier New">&lt;meta name="foo" content="bar"&gt;</font>）从基础页面传递信息到装饰器。作为一个例子，下面我们使用一个meta标签来定义HTML页面的作者。 </p>
		<pre>
				<code>&lt;html&gt;<br /> &lt;meta name="author" content="test@example.com"&gt;<br /> &lt;head&gt;<br /> &lt;title&gt;Simple Document&lt;/title&gt;<br /> &lt;/head&gt;<br /> &lt;body&gt;<br /> Hello World! &lt;br /&gt;<br /> &lt;%= 1+1 %&gt;<br /> &lt;/body&gt;<br />&lt;/html&gt;</code>
		</pre>
		<p>我们定义一个“smart”装饰器来研究meta标签，如果出现这个标签，则可以得到一个相应的HTML：</p>
		<pre>
				<code>&lt;%@ taglib uri="sitemesh-decorator" prefix="decorator" %&gt;<br /> &lt;decorator:usePage id="myPage" /&gt;<br /> &lt;html&gt;<br /> &lt;head&gt;<br /> &lt;title&gt;My Site -<br /> &lt;decorator:title default="Welcome!" /&gt;<br /> &lt;/title&gt;<br /> &lt;decorator:head /&gt;<br /> &lt;/head&gt;<br /><br /> &lt;body&gt;<br /> &lt;h1&gt;&lt;decorator:title default="Welcome!" /&gt;&lt;/h1&gt;<br /> &lt;h3&gt;<br /> &lt;a href="mailto:&lt;decorator:getProperty property="meta.author" <br /> default="staff@example.com" /&gt;"&gt;<br /> &lt;decorator:getProperty property="meta.author"<br /> default="staff@example.com" /&gt;<br /> &lt;/a&gt;&lt;/h3&gt;&lt;hr /&gt;<br /> &lt;decorator:body /&gt;<br /> &lt;p&gt;&lt;small&gt;<br /> (&lt;a href="http://www.zhmy.com/?printable=true"&gt;printable version&lt;/a&gt;<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://218.249.43.230/images/smileys/wink.gif" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" /><br /> &lt;/small&gt;<br /> &lt;/p&gt;<br /> &lt;/body&gt;<br /> &lt;/html&gt;</code>
		</pre>
		<p>可以看到我们使用了<font face="Courier New">getProperty标签</font>的一个默认属性——如果没有指定 author，我们就设定其为staff。如果你决定使用这个模型储存页面的meta数据，你或许需要和你的开发伙伴一起来确定将使用什么标签以及如何使 用他们。简单的，你或许想要使用meta标签来描述诸如页面作者及时间戳之类的东西。更复杂一些，你或许会想像XML文件一样标准化的管理你的站点导航， 同时使用meta标签来通过页面节点转到装饰器。（At the complex end, you may do things like standardize on an XML file to manage your site navigation and use a <code><font face="新宋体">meta</font></code> tag to pass the page's node to the decorator. ）</p>
		<p>图六显示了应用上面的装饰器JSP页面之后生成的结果。</p>
		<p>
				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig6.gif" width="392" onload="javascript:if(this.width&gt;420){this.resized=true;this.style.width=420;}" />
				<br />
				<em>图六：meta标签显示</em>
		</p>
		<p>这些页面属性非常强大，并且拥有着很多不同的特性，并不仅止于meta标签（<a href="http://www.opensymphony.com/sitemesh/api/com/opensymphony/module/sitemesh/HTMLPage.html"> 常用页面特性列表</a>）。使用SiteMesh一段时间之后，你就会开始思考HTML和JSP作为一种简单标记语言的机制——接近最原始的HTML——无需操作就可以完整的切换到XML/XSL 或其他模版引擎。</p>
		<h2 id="Summary">小结</h2>
		<p>综上所述，SiteMesh 提供了一个强大、易用、易结合的机制来使用页面模版。可以想象，它将会有很广泛的用户群。例如，你可以定义一个装饰器针对不同的浏览器输出额外的页面调试 信息（和特定web浏览器结合之后将产生一个特别的功能，你可以强制指定使用某一种用户代理）。你也可以定义一个装饰器产生stripped-down XML输出，用来进行简单的自动化测试。你甚至可以使用装饰器从其他页面提取内容，例如输出到一些简单的门户容器。</p>
		<p>从<em>sitemesh-blank.war</em>入手比较容易，但我建议学习 <em>sitemesh-example.war</em> 以获取更多的特性和思想。</p>
		<p>不论你如何使用SiteMesh，我都发现它将大量的代码从表现层中移到我的装饰器中，而无需学习一种新的编程语言或是模版系统。 </p>
		<p>对了，作为最后的补充，如果你仍然对组合建立web页面感兴趣，可以查看<a href="http://home.worldonline.dk/viksoe/asmil.htm">home.worldonline.dk/viksoe/asmil.htm</a> 。</p>
		<p>祝好运并享受编程的乐趣！</p>
		<!-- AddThis Bookmark Post Button BEGIN -->
<img src ="http://www.blogjava.net/martinyuan/aggbug/271937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/martinyuan/" target="_blank">Martin Yuan</a> 2008-01-10 16:16 <a href="http://www.blogjava.net/martinyuan/articles/271937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>