﻿<?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-&lt;h3 style="font-family: Comic Sans MS"&gt;&lt;font color="#FA1A0A" size="10"&gt;︻┳═一Java&lt;/font&gt;&lt;/h3&gt;-文章分类-Spring</title><link>http://www.blogjava.net/rain1102/category/14842.html</link><description>&lt;b&gt;&lt;font color="#3C1435"&gt;08年奋斗目标：&lt;/font&gt;&lt;font color="#F70E0A"&gt;赚钱买个房子！&lt;/font&gt;&lt;/b&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 22 Apr 2008 07:24:12 GMT</lastBuildDate><pubDate>Tue, 22 Apr 2008 07:24:12 GMT</pubDate><ttl>60</ttl><item><title>项目中封装Spring中的测试基类</title><link>http://www.blogjava.net/rain1102/articles/194490.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Mon, 21 Apr 2008 05:15:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/194490.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/194490.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/194490.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/194490.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/194490.html</trackback:ping><description><![CDATA[<p>package com.founder.common;</p>
<p>import <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.text.SimpleDateFormat;<br />
import <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.util.TimeZone;</p>
<p>import org.hibernate.SessionFactory;<br />
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;</p>
<p>/**<br />
&nbsp;* This class is the base class of all the tests, <br />
&nbsp;* we can use the dependency injection functionality of spring in all the tests,<br />
&nbsp;* and the default transaction mode is rollback, so we don't need to write special code to restore data after calling some methods affected database data. <br />
&nbsp;* <br />
&nbsp;* @author Rui Zhou, Copyright &#169; 2008 foundersoftware. All Rights Reserved.<br />
&nbsp;* @version 1.00, 2008-03-22 15:46<br />
&nbsp;*/<br />
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {<br />
&nbsp;<br />
&nbsp;protected SimpleDateFormat sdf;<br />
&nbsp;<br />
&nbsp;public SpringTestCaseBase() {<br />
&nbsp;&nbsp;// query the protected variables to implement denpendency injection automatically,<br />
&nbsp;&nbsp;// so we don't need to write settor and gettor methods anymore.<br />
&nbsp;&nbsp;this.setPopulateProtectedVariables(true);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;sdf = new SimpleDateFormat("yyyy-MM-dd");<br />
&nbsp;&nbsp;sdf.setTimeZone(TimeZone.getDefault());<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;protected String[] getConfigLocations() {<br />
&nbsp;&nbsp;return new String[] { "file:WebRoot/WEB-INF/applicationContext*.xml"};<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;<br />
&nbsp;protected void flushSession(){<br />
&nbsp;&nbsp;SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionFactory.getCurrentSession().flush();<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
</p><img src ="http://www.blogjava.net/rain1102/aggbug/194490.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2008-04-21 13:15 <a href="http://www.blogjava.net/rain1102/articles/194490.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Servlet(或者Filter，或者Listener)中使用spring的IOC容器 </title><link>http://www.blogjava.net/rain1102/articles/175495.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 15 Jan 2008 08:42:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/175495.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/175495.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/175495.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/175495.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/175495.html</trackback:ping><description><![CDATA[<p>在servlet或者filter或者Listener中使用spring的IOC容器的方法是：</p>
<p>WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());&nbsp;</p>
<p>由于spring是注入的对象放在ServletContext中的，所以可以直接在ServletContext取出WebApplicationContext 对象：</p>
<p>WebApplicationContext webApplicationContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);</p>
<p>事实上WebApplicationContextUtils.getWebApplicationContext方法就是使用上面的代码实现的，建议使用上面上面的静态方法&nbsp;</p>
<br />
注意：在使用webApplicationContext.getBean("ServiceName")的时候，前面强制转化要使用接口，如果使用实现类会报类型转换错误。如：<br />
LUserService&nbsp;userService ＝ (LUserService) webApplicationContext.getBean("userService");<img src ="http://www.blogjava.net/rain1102/aggbug/175495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2008-01-15 16:42 <a href="http://www.blogjava.net/rain1102/articles/175495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的复杂用法HibernateCallback</title><link>http://www.blogjava.net/rain1102/articles/170638.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Wed, 26 Dec 2007 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/170638.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/170638.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/170638.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/170638.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/170638.html</trackback:ping><description><![CDATA[<p style="text-indent: 21pt; line-height: 15.7pt">HibernateTemplate<span style="font-family: 宋体">还提供一种更加灵活的方式来操作数据库，通过这种方式可以完全使用</span>Hibernate<span style="font-family: 宋体">的操作方式。</span>HibernateTemplate<span style="font-family: 宋体">的灵活访问方式是通过如下两个方法完成：</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>Object execute(HibernateCallback action)</p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>List execute(HibernateCallback action)</p>
<p style="text-indent: 21pt; line-height: 15.7pt"><span style="font-family: 宋体">这两个方法都需要一个</span>HibernateCallback<span style="font-family: 宋体">的实例，</span>HibernateCallback<span style="font-family: 宋体">实例可在任何有效的</span>Hibernate<span style="font-family: 宋体">数据访问中使用。程序开发者通过</span>HibernateCallback<span style="font-family: 宋体">，可以完全使用</span>Hibernate<span style="font-family: 宋体">灵活的方式来访问数据库，解决</span>Spring<span style="font-family: 宋体">封装</span>Hibernate<span style="font-family: 宋体">后灵活性不足的缺陷。</span>HibernateCallback<span style="font-family: 宋体">是一个接口，该接口只有一个方法</span>doInHibernate(org.hibernate.Session&nbsp;session)<span style="font-family: 宋体">，该方法只有一个参数</span>Session<span style="font-family: 宋体">。</span></p>
<p style="text-indent: 21pt; line-height: 15.7pt"><span style="font-family: 宋体">通常，程序中采用实现</span>HibernateCallback<span style="font-family: 宋体">的匿名内部类来获取</span>HibernateCallback<span style="font-family: 宋体">的实例，方法</span>doInHibernate<span style="font-family: 宋体">的方法体就是</span>Spring<span style="font-family: 宋体">执行的持久化操作。具体代码如下：</span></p>
<p>public class PersonDaoImpl implements PersonDao</p>
<p>{<br />
&nbsp;// 私有实例变量保存SessionFactory<br />
&nbsp;private SessionFactory sessionFactory;<br />
&nbsp;// 依赖注入必须的setter方法<br />
&nbsp;public void setSessionFactory(SessionFactory sessionFactory){<br />
&nbsp;&nbsp;this.sessionFactory = sessionFactory;<br />
&nbsp;}<br />
&nbsp;/**<br />
&nbsp; * <br />
&nbsp; * 通过人名查找所有匹配该名的Person实例<br />
&nbsp; * <br />
&nbsp; * @param name<br />
&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 匹配的人名<br />
&nbsp; * <br />
&nbsp; * @return 匹配该任命的全部Person集合<br />
&nbsp; * <br />
&nbsp; */<br />
&nbsp;public List findPersonsByName(final String name){<br />
&nbsp;&nbsp;// 创建HibernateTemplate实例<br />
&nbsp;&nbsp;HibernateTemplate hibernateTemplate =new HibernateTemplate(this.sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 返回HibernateTemplate的execute的结果<br />
&nbsp;&nbsp;return (List) hibernateTemplate.execute(<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 创建匿名内部类<br />
&nbsp;&nbsp;&nbsp;&nbsp;new HibernateCallback(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public Object doInHibernate(Session session) throws HibernateException{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 使用条件查询的方法返回<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List result = session.createCriteria(Person.class)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.add(Restrictions.like("name", name+"%").list();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
</p>
<span style="font-family: 宋体">注意：方法</span><span lang="EN-US">doInHibernate</span><span style="font-family: 宋体">方法内可以访问</span><span lang="EN-US">Session</span><span style="font-family: 宋体">，该</span><span lang="EN-US">Session</span><span style="font-family: 宋体">对象是绑定到该线程的</span><span lang="EN-US">Session</span><span style="font-family: 宋体">实例。该方法内的持久层操作，与不使用</span><span lang="EN-US">Spring</span><span style="font-family: 宋体">时的持久层操作完全相同。这保证对于复杂的持久层访问，依然可以使用</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体">的访问方式。</span><img src ="http://www.blogjava.net/rain1102/aggbug/170638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-26 17:09 <a href="http://www.blogjava.net/rain1102/articles/170638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HibernateTemplate的常规用法</title><link>http://www.blogjava.net/rain1102/articles/170633.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Wed, 26 Dec 2007 08:46:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/170633.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/170633.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/170633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/170633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/170633.html</trackback:ping><description><![CDATA[<p style="text-indent: 21pt; line-height: 15.7pt">HibernateTemplate<span style="font-family: 宋体">提供非常多的常用方法来完成基本的操作，比如通常的增加、删除、修改、查询等操作，</span>Spring 2.0<span style="font-family: 宋体">更增加对命名</span>SQL<span style="font-family: 宋体">查询的支持，也增加对分页的支持。大部分情况下，使用</span>Hibernate<span style="font-family: 宋体">的常规用法，就可完成大多数</span>DAO<span style="font-family: 宋体">对象的</span>CRUD<span style="font-family: 宋体">操作。下面是</span>HibernateTemplate<span style="font-family: 宋体">的常用方法简介：</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>void delete(Object entity)<span style="font-family: 宋体">：删除指定持久化实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>deleteAll(Collection entities)<span style="font-family: 宋体">：删除集合内全部持久化类实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>find(String queryString)<span style="font-family: 宋体">：根据</span>HQL<span style="font-family: 宋体">查询字符串来返回实例集合</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>findByNamedQuery(String queryName)<span style="font-family: 宋体">：根据命名查询返回实例集合</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>get(Class entityClass, Serializable id)<span style="font-family: 宋体">：根据主键加载特定持久化类的实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>save(Object entity)<span style="font-family: 宋体">：保存新的实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>saveOrUpdate(Object entity)<span style="font-family: 宋体">：根据实例状态，选择保存或者更新</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>update(Object entity)<span style="font-family: 宋体">：更新实例的状态，要求</span>entity<span style="font-family: 宋体">是持久状态</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>setMaxResults(int maxResults)<span style="font-family: 宋体">：设置分页的大小</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/170633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-26 16:46 <a href="http://www.blogjava.net/rain1102/articles/170633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse 开发 SSH 整合时 java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit 解决方案 </title><link>http://www.blogjava.net/rain1102/articles/169853.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Sun, 23 Dec 2007 12:47:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/169853.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/169853.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/169853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/169853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/169853.html</trackback:ping><description><![CDATA[ERROR [org.hibernate.proxy.BasicLazyInitializer] - CGLIB Enhancement failed: dao.User<br />
<a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V<br />
&nbsp;at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77) <br />
<span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">Spring </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">和</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> Hibernate </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">共用的一些</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> jar </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">文件发生了版本冲突</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">, </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">删除</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> WEB-INF/lib/asm-2.2.3.jar </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">然后重启</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> Tomcat.</span><br />
<span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">asm-2.2.3.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-attrs.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-commons-2.2.3.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-util-2.2.3.jar</span><img src ="http://www.blogjava.net/rain1102/aggbug/169853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-23 20:47 <a href="http://www.blogjava.net/rain1102/articles/169853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>采用GenericManager做业务处理的时候CGLIB报错. </title><link>http://www.blogjava.net/rain1102/articles/169846.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Sun, 23 Dec 2007 12:26:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/169846.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/169846.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/169846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/169846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/169846.html</trackback:ping><description><![CDATA[项目中我把Service这层的类改了一下.定义了两个Service的父类.一个是:<br />
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;GenericManager&lt;T,&nbsp;PK&nbsp;</span><span class="keyword">extends</span><span>&nbsp;Serializable&gt;&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;List&lt;T&gt;&nbsp;getAll(); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;T&nbsp;get(PK&nbsp;id); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>.......基本的CRUD方法 &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
<br />
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;GenericManagerImpl&lt;T,&nbsp;PK&nbsp;</span><span class="keyword">extends</span><span>&nbsp;Serializable&gt;&nbsp;</span><span class="keyword">implements</span><span>&nbsp;GenericManager&lt;T,&nbsp;PK&gt;&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">protected</span><span>&nbsp;BaseGenericHibernateDAO&lt;T,&nbsp;PK&gt;&nbsp;baseGenericHibernateDAO; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;GenericManagerImpl(BaseGenericHibernateDAO&lt;T,&nbsp;PK&gt;&nbsp;baseGenericHibernateDAO)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span class="keyword">this</span><span>.baseGenericHibernateDAO&nbsp;=&nbsp;baseGenericHibernateDAO; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>对应实现上面的接口CRUD方法 &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
但是现在项目启动的时候抛出一个如下的错误:<br />
<li class="alt"><span><span>Caused&nbsp;by:&nbsp;org.springframework.aop.framework.AopConfigException:&nbsp;Couldn't&nbsp;generate&nbsp;CGLIB&nbsp;subclass&nbsp;of&nbsp;</span><span class="keyword">class</span><span>&nbsp;[</span><span class="keyword">class</span><span>&nbsp;com.xxxx.user.service.impl.UserManagerImpl]:&nbsp;Common&nbsp;causes&nbsp;of&nbsp;</span><span class="keyword">this</span><span>&nbsp;problem&nbsp;include&nbsp;using&nbsp;a&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;or&nbsp;a&nbsp;non-visible&nbsp;</span><span class="keyword">class</span><span>;&nbsp;nested&nbsp;exception&nbsp;is&nbsp;java.lang.IllegalArgumentException:&nbsp;Superclass&nbsp;has&nbsp;no&nbsp;</span><span class="keyword">null</span><span>&nbsp;constructors&nbsp;but&nbsp;no&nbsp;arguments&nbsp;were&nbsp;given &nbsp;&nbsp;</span></span></li>
<li class=""><span>Caused&nbsp;by:&nbsp;java.lang.IllegalArgumentException:&nbsp;Superclass&nbsp;has&nbsp;no&nbsp;</span><span class="keyword">null</span><span>&nbsp;constructors&nbsp;but&nbsp;no&nbsp;arguments&nbsp;were&nbsp;given &nbsp;&nbsp;</span></span></li>
<li class="alt"><span>at&nbsp;net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:</span><span class="number">718</span><span>)&nbsp;&nbsp;</span></li>
<br />
<span style="color: red">是Spring AOP的问题.主要是出现在事务这块,由于我用的是Spring2.0 AOP 来声明事务.在声明事务的时候我把taget-prent-class="true" 了,但事实上不能为true.去掉这个就OK了因为要针对接口代理.</span><br /><img src ="http://www.blogjava.net/rain1102/aggbug/169846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-23 20:26 <a href="http://www.blogjava.net/rain1102/articles/169846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring事务、异常</title><link>http://www.blogjava.net/rain1102/articles/130588.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Mon, 16 Jul 2007 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/130588.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/130588.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/130588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/130588.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/130588.html</trackback:ping><description><![CDATA[<p><span>Spring</span><span>的事务实现采用基于</span><span>AOP</span><span>的拦截器来实现，如果没有在事务配置的时候注明回滚的</span><span>checked exception</span><span>，那么只有在发生了</span><span>unchecked exception</span><span>的时候，才会进行事务回滚。因此在</span><span>DAO</span><span>层和</span><span>service</span><span>层，最好抛出</span><span>unckecked exception</span><span>，毕竟对于数据库操作，使用</span><span>unckecked exception</span><span>更加合适，这个方面的例子</span><span>hibernate</span><span>就是一个，在</span><span>hibernate2</span><span>中，</span><span>HibernateException</span><span>还是</span><span>checked exceptions</span><span>，但是到了</span><span>hibernate3</span><span>中就成了</span><span>unchecked exceptions</span><span>，因为对于数据库操作来说，一旦出现异常，就是比较严重的错误，而且在</span><span>client</span><span>端基本上是无能为力的，所以使用</span><span>unchecked exceptions</span><span>更加合适。</span></p>
<p><span>另外，在</span><span>DAO</span><span>和</span><span>service</span><span>层的代码中，除非是为了异常的转化、重新抛出，否则不要捕捉和处理异常，否则</span><span>AOP</span><span>在拦截的时候就不能捕捉到异常，也就不能正确执行回滚。这一点通常很容易被忽视，只有在明白了</span><span>spring</span><span>的事务处理机制后，才能领会到。</span></p>
<p><span>对于</span><span>hibernate</span><span>的异常，</span><span>spring</span><span>会包装</span><span>hibernate</span><span>的</span><span>upckecked hibernateException</span><span>到</span><span>DAOAccessException</span><span>，并且抛出，在事务管理层，一旦接收到</span><span>DAOAccessException</span><span>就会触发事务的回滚，同时该异常会继续向上层抛出，供上层进一步处理，比如在</span><span>UI</span><span>层向用户反馈错误信息等。<br>在spring的事务管理环境下，使用unckecked exception可以极大地简化异常的处理，只需要在事务层声明可能抛出的异常（这里的异常可以是自定义的unckecked exception体系），在所有的中间层都只是需要简单throws即可，不需要捕捉和处理，直接到最高层，比如UI层再进行异常的捕捉和处理。<br></span></p><img src ="http://www.blogjava.net/rain1102/aggbug/130588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-07-16 15:23 <a href="http://www.blogjava.net/rain1102/articles/130588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中的所有事务策略</title><link>http://www.blogjava.net/rain1102/articles/130075.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 13 Jul 2007 06:05:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/130075.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/130075.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/130075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/130075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/130075.html</trackback:ping><description><![CDATA[Spring中的所有<nobr>事务</nobr>策略：<br>
<ul>
    <li>PROPAGATION_REQUIRED--支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。
    <li>PROPAGATION_SUPPORTS--支持当前事务，如果当前没有事务，就以非事务方式执行。
    <li>PROPAGATION_MANDATORY--支持当前事务，如果当前没有事务，就抛出异常。
    <li>PROPAGATION_REQUIRES_NEW--新建事务，如果当前存在事务，把当前事务挂起。
    <li>PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。
    <li>PROPAGATION_NEVER--以非事务方式执行，如果当前存在事务，则抛出异常。
    <li>PROPAGATION_NESTED--如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则进行与PROPAGATION_REQUIRED类似的操作。 </li>
</ul><img src ="http://www.blogjava.net/rain1102/aggbug/130075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-07-13 14:05 <a href="http://www.blogjava.net/rain1102/articles/130075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Open Session in Test 及自动Rollback</title><link>http://www.blogjava.net/rain1102/articles/117541.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 15 May 2007 03:09:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/117541.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/117541.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/117541.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/117541.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/117541.html</trackback:ping><description><![CDATA[又是来自Spring这个神奇国度的东西， 你可以让testCase继承于AbstractTransactionalDataSourceSpringContextTests，就可以做到Open Session in Test ，解决Hibernate的lazy-load问题；而且接管原来的DAO里的事务控制定义，通过setDefaultRollback(boolean)方法控制最后回滚还是提交，如果默认为回滚，则测试产生数据变动不会影响数据库内数据。<br>&nbsp;<br>如果不能继承于这个基类，可以自己简单编写，代码是这样的：<br>&nbsp;&nbsp;<span style="COLOR: #008000"> protected PlatformTransactionManager transactionManager;<br>&nbsp;&nbsp; protected TransactionStatus transactionStatus;<br>&nbsp;&nbsp; protected boolean defaultRollback = true;<br>&nbsp;&nbsp; public void setUp()<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager = (PlatformTransactionManager) ctx.getBean("transactionManager");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; public void tearDown()<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (defaultRollback)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager.rollback(this.transactionStatus);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager.commit(this.transactionStatus);<br>&nbsp;&nbsp;&nbsp; }<br></span>(注，hibernate太奸诈了，如果全部默认回滚，只会在session里干活，一点不写数据库，达不到完全的测试效果。)<img src ="http://www.blogjava.net/rain1102/aggbug/117541.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-05-15 11:09 <a href="http://www.blogjava.net/rain1102/articles/117541.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Spring中的回滚问题AbstractTransactionalDataSourceSpringContextTests</title><link>http://www.blogjava.net/rain1102/articles/117518.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 15 May 2007 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/117518.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/117518.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/117518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/117518.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/117518.html</trackback:ping><description><![CDATA[AbstractTransactionalDataSourceSpringContextTests缺乏对hibernate session的处理，需要对其进行扩展，扩展基本思路是在事务开始后，结束前把测试方法包装在
<p>HibernateTemaplate.executeWithSession(...){ <br>public Object doInHibernate(Session session) { <br>runTest(); <br>session.flush();//synchornize database, errors will be reported. <br>session.clear();}...}<br>而AbstractTransactionalDataSourceSpringContextTests只要你不调用super.setDefaultRollback(false);这个基类默认就会回滚! 于是由此产生hibernate偷懒,无法发现数据库操作,然后我们建议你在测试中显示调用session.flush <br>或者参杂一些查询调用(其实也是为了触发session.flush)。</p>
<p>不过这里面也有些陷阱:如果你的测试还是会把数据写入了数据库的话,可能是由于你加载的spring配置文件里有多个事务管理器或session工厂,从而导致AbstractTransactionalDataSourceSpringContextTests没有获得正确的TransactionManager或SessionFactory,所以就没能回滚不过这种错误也不太容易犯,因为AbstractTransactionalDataSourceSpringContextTests默认按类型组装,如果她发现有多个TransactionManager类型的bean是要报错的,此时你需要调用setAutowireMode(this.AUTOWIRE_BY_NAME);使其按名称组装。<br><br>另外值得注意的是，使用MYSQL时候表的类型选择。例如</p>
<p><span style="COLOR: rgb(0,0,255)">CREATE</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">TABLE</span><span style="COLOR: rgb(0,0,0)">&nbsp;`myisam`&nbsp;(<br>&nbsp;&nbsp;`id`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">int</span><span style="COLOR: rgb(0,0,0)">(</span><span style="FONT-WEIGHT: bold; COLOR: rgb(128,0,0)">11</span><span style="COLOR: rgb(0,0,0)">)&nbsp;</span><span style="COLOR: rgb(128,128,128)">NOT</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">NULL</span><span style="COLOR: rgb(0,0,0)">&nbsp;auto_increment,<br>&nbsp;&nbsp;`name`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">varchar</span><span style="COLOR: rgb(0,0,0)">(</span><span style="FONT-WEIGHT: bold; COLOR: rgb(128,0,0)">100</span><span style="COLOR: rgb(0,0,0)">)&nbsp;</span><span style="COLOR: rgb(0,0,255)">default</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">NULL</span><span style="COLOR: rgb(0,0,0)">,<br>&nbsp;&nbsp;`content`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">text</span><span style="COLOR: rgb(0,0,0)">,<br>&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">PRIMARY</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">KEY</span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;(`id`)<br>)&nbsp;ENGINE</span><span style="COLOR: rgb(128,128,128)">=</span><span style="COLOR: rgb(0,0,0)">MyISAM&nbsp;</span><span style="COLOR: rgb(0,0,255)">DEFAULT</span><span style="COLOR: rgb(0,0,0)">&nbsp;CHARSET</span><span style="COLOR: rgb(128,128,128)">=</span><span style="COLOR: rgb(0,0,0)">gbk;<br>这时候应该把类型改为InnoDB。</span></p>
<p><span style="COLOR: rgb(0,0,0)">MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎：&#183; MyISAM管理非事务表。它提供高速存储和检索，以及全文搜索能力。MyISAM在所有MySQL配置里被支持，它是默认的存储引擎，除非你配置 MySQL默认使用另外一个引擎。 &#183;MEMORY存储引擎提供&#8220;内存中&#8221;表。MERGE存储引擎允许集合将被处理同样的MyISAM表作为一个单独的表。就像MyISAM一样， MEMORY和MERGE存储引擎处理非事务表，这两个引擎也都被默认包含在MySQL中。 释：MEMORY存储引擎正式地被确定为HEAP引擎。&#183; InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系统发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所 有MySQL 5.1二进制分发版里，你可以按照喜好通过配置MySQL来允许或禁止任一引擎。&#183;EXAMPLE存储引擎是一个&#8220;存根&#8221;引擎，它不做什么。你可以用这个 引擎创建表，但没有数据被存储于其中或从其中检索。</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/117518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-05-15 10:06 <a href="http://www.blogjava.net/rain1102/articles/117518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi的配置</title><link>http://www.blogjava.net/rain1102/articles/107142.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Thu, 29 Mar 2007 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/107142.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/107142.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/107142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/107142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/107142.html</trackback:ping><description><![CDATA[<p>applicationContext-acegi-security.xml<br /><strong>1.filterChainProxy配置<br /></strong>&lt;bean id="<font style="BACKGROUND-COLOR: #ffffff" color="#800080">filterChainProxy</font>" class="org.acegisecurity.util.FilterChainProxy"&gt;<br />  &lt;property name="<font style="BACKGROUND-COLOR: #ffffff" color="#006400">filterInvocationDefinitionSource</font>"&gt;<br />   &lt;value&gt;<br />    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />    PATTERN_TYPE_APACHE_ANT<br />    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor<br />   &lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>2.httpSessionContextIntegrationFilter配置</strong><br />&lt;bean id="<font color="#800080">httpSessionContextIntegrationFilter</font>" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/&gt;<br /><br />3.logoutFilter配置<br />&lt;bean id="<font color="#800080">logoutFilter</font>" class="org.acegisecurity.ui.logout.LogoutFilter"&gt;<br />  &lt;constructor-arg value="/index.jsp"/&gt; &lt;!-- URL redirected to after logout --&gt;<br />  &lt;constructor-arg&gt;<br />   &lt;list&gt;<br />    &lt;ref bean="<font color="#006400">rememberMeServices</font>"/&gt;<br />    &lt;bean class="<font color="#006400">org.acegisecurity.ui.logout.SecurityContextLogoutHandler</font>"/&gt;<br />   &lt;/list&gt;<br />  &lt;/constructor-arg&gt;<br /> &lt;/bean&gt;<br /><br /><strong>4.authenticationProcessingFilter配置<br /></strong>&lt;bean id="<font color="#800080">authenticationProcessingFilter</font>" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />  &lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />  &lt;property name="<font color="#006400">authenticationFailureUrl</font>" value="/login.jsp?login_error=1"/&gt;<br />  &lt;property name="<font color="#006400">defaultTargetUrl</font>" value="/"/&gt;<br />  &lt;property name="<font color="#006400">filterProcessesUrl</font>" value="/j_acegi_security_check"/&gt;<br />  &lt;property name="<font color="#006400">rememberMeServices</font>" ref="rememberMeServices"/&gt;<br /> &lt;/bean&gt;<br /><br /><strong>5.securityContextHolderAwareRequestFilter配置</strong><br />&lt;bean id="<font color="#800080">securityContextHolderAwareRequestFilter</font>" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/&gt;<br /><br /><strong>6.rememberMeProcessingFilter配置</strong><br />&lt;bean id="<font color="#800080">rememberMeProcessingFilter</font>" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"&gt;<br />  &lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />  &lt;property name="<font color="#006400">rememberMeServices</font>" ref="rememberMeServices"/&gt;<br /> &lt;/bean&gt;<br /><br /><strong>7.anonymousProcessingFilter配置</strong><br />&lt;bean id="<font color="#800080">anonymousProcessingFilter</font>" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"&gt;<br />  &lt;property name="<font color="#006400">key</font>" value="changeThis"/&gt;<br />  &lt;property name="<font color="#006400">userAttribute</font>" value="anonymousUser,ROLE_ANONYMOUS"/&gt;<br /> &lt;/bean&gt;<br /><br /><strong>8.exceptionTranslationFilter配置</strong><br />&lt;bean id="<font color="#800080">exceptionTranslationFilter</font>" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;<br />  &lt;property name="<font color="#006400">authenticationEntryPoint</font>"&gt;<br />   &lt;bean class="<font color="#006400">org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint</font>"&gt;<br />    &lt;property name="<font color="#006400">loginFormUrl</font>" value="/login.jsp"/&gt;<br />    &lt;property name="<font color="#008000">forceHttps</font>" value="false"/&gt;<br />   &lt;/bean&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#006400">accessDeniedHandler</font>"&gt;<br />   &lt;bean class="<font color="#006400">org.acegisecurity.ui.AccessDeniedHandlerImpl</font>"&gt;<br />    &lt;property name="<font color="#006400">errorPage</font>" value="/accessDenied.jsp"/&gt;<br />   &lt;/bean&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>9.filterInvocationInterceptor配置</strong><br />&lt;bean id="<font color="#800080">filterInvocationInterceptor</font>" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />  &lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />  &lt;property name="<font color="#006400">accessDecisionManager</font>" ref="accessDecisionManager"/&gt;<br />  &lt;property name="<font color="#006400">objectDefinitionSource</font>"&gt;<br />   &lt;value&gt;<br />    PATTERN_TYPE_APACHE_ANT<br />    /mainFrame.html=admin,user<br />    /文件夹1/*.html*=admin,user<br />    /文件夹2/*.html*=admin,user<br />    /文件夹3/*.html*=admin<br />    /accessDenied.jsp*=ROLE_ANONYMOUS<br />   &lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>10.</strong><font color="#000000"><strong>accessDecisionManager配置</strong><br /></font>&lt;bean id="<font color="#800080">accessDecisionManager</font>" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />  &lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />  &lt;property name="decisionVoters"&gt;<br />   &lt;list&gt;<br />    &lt;bean class="org.acegisecurity.vote.RoleVoter"&gt;<br />     &lt;property name="rolePrefix" value=""/&gt;<br />    &lt;/bean&gt;<br />    &lt;bean class="org.acegisecurity.vote.AuthenticatedVoter"/&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>11.rememberMeServices配置</strong></p>
		<p> &lt;bean id="<font color="#800080">rememberMeServices</font>" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"&gt;<br />  &lt;property name="userDetailsService" ref="userDetailsService"/&gt;<br />  &lt;property name="key" value="changeThis"/&gt;<br /> &lt;/bean&gt;<br /><br /><strong>12.authenticationManager配置</strong></p>
		<p> &lt;bean id="<font color="#800080">authenticationManager</font>" class="org.acegisecurity.providers.ProviderManager"&gt;<br />  &lt;property name="providers"&gt;<br />   &lt;list&gt;<br />    &lt;ref local="daoAuthenticationProvider"/&gt;<br />    &lt;bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"&gt;<br />     &lt;property name="key" value="changeThis"/&gt;<br />    &lt;/bean&gt;<br />    &lt;bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"&gt;<br />     &lt;property name="key" value="changeThis"/&gt;<br />    &lt;/bean&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>13.daoAuthenticationProvider配置</strong></p>
		<p> &lt;bean id="<font color="#800080">daoAuthenticationProvider</font>" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />  &lt;property name="userDetailsService" ref="userDetailsService"/&gt;<br />  &lt;property name="userCache"&gt;<br />   &lt;bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;<br />    &lt;property name="cache"&gt;<br />     &lt;bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />      &lt;property name="cacheManager"&gt;<br />       &lt;bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;<br />        &lt;property name="configLocation" value="classpath:ehcache.xml"/&gt;<br />       &lt;/bean&gt;<br />      &lt;/property&gt;<br />      &lt;property name="cacheName" value="userCache"/&gt;<br />     &lt;/bean&gt;<br />    &lt;/property&gt;<br />   &lt;/bean&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>14.methodSecurityInterceptor配置</strong><br /> <br /> &lt;bean id="<font color="#800080">methodSecurityInterceptor</font>" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />  &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />  &lt;property name="accessDecisionManager" ref="accessDecisionManager"/&gt;<br />  &lt;property name="objectDefinitionSource"&gt;<br />    &lt;value&gt;<br />     com.rain.wsh.service.IUserService.get*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.create*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.update*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.delete*=IS_AUTHENTICATED_ANONYMOUSLY <br />   &lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>15.loggerListener配置</strong></p>
		<p> &lt;!-- This bean is optional; it isn't used by any other bean as it only listens and logs --&gt;<br /> &lt;bean id="<font color="#800080">loggerListener</font>" class="org.acegisecurity.event.authentication.LoggerListener"/&gt;<br /><br />注:userDetailsService定义为:<br />&lt;bean id="<font color="#800080">userDetailsService</font>" class="com.rain.wsh.service.impl.UserDetailsServiceImpl"/&gt;<br /><br />package com.rain.wsh.service.impl;</p>
		<p>import org.acegisecurity.userdetails.UserDetails;<br />import org.acegisecurity.userdetails.UserDetailsService;<br />import org.acegisecurity.userdetails.UsernameNotFoundException;<br />import org.springframework.dao.DataAccessException;</p>
		<p>import com.rain.wsh.dao.IUserDAO;</p>
		<p>public class UserDetailsServiceImpl implements <font color="#800080">UserDetailsService</font> {<br /> private final Logger log = Logger.getLogger(getClass());<br /> <br /> private IUserDAO userDAO;<br /> <br /> /**<br />  * @return the userDAO<br />  */<br /> public IUserDAO getUserDAO() {<br />  return userDAO;<br /> }</p>
		<p> /**<br />  * @param userDAO the userDAO to set<br />  */<br /> public void setUserDAO(IUserDAO userDAO) {<br />  this.userDAO = userDAO;<br /> }<br /> <br /> /*<br />  * (non-Javadoc)<br />  * @see org.acegisecurity.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)<br />  */<br /> public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {<br />  <br />  UserDetails user = userDAO.getUserByName(userName);<br />  if (user == null) {<br />   log.error("The user was not found:" + userName);<br />   throw new UsernameNotFoundException("The user was not found:" + userName);<br />  }<br />  return user;<br /> }</p>
		<p>}<br /><br />注意user必须实现<font color="#006400">Serializable, UserDetails</font><br /></p><img src ="http://www.blogjava.net/rain1102/aggbug/107142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-03-29 10:32 <a href="http://www.blogjava.net/rain1102/articles/107142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中的一些重要配置</title><link>http://www.blogjava.net/rain1102/articles/107136.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Thu, 29 Mar 2007 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/107136.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/107136.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/107136.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/107136.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/107136.html</trackback:ping><description><![CDATA[<p>
				<strong>1.读取属性文件<br /></strong>&lt;!-- for properties files --&gt;<br /> &lt;bean id="propertyConfigurer"<br />  class="<font color="#006400">org.springframework.beans.factory.config.PropertyPlaceholderConfigurer</font>"&gt;<br />  &lt;property name="<font color="#006400">locations</font>"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;<font color="#006400">classpath:*.properties</font>&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>2.配置数据源</strong><br />&lt;!-- for dataSource --&gt;<br />&lt;bean id="dataSource"<br />  class="<font color="#006400">com.mchange.v2.c3p0.ComboPooledDataSource</font>" <br />  destroy-method="close"&gt;<br />  &lt;property name="<font color="#006400">driverClass</font>" value="${jdbc.driver}" /&gt;<br />  &lt;property name="<font color="#006400">jdbcUrl</font>" value="${jdbc.url}" /&gt;</p>
		<p>  &lt;property name="<font color="#006400">properties</font>"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="c3p0.minPoolSize"&gt;${hibernate.c3p0.minPoolSize}&lt;/prop&gt;<br />    &lt;prop key="hc3p0.maxPoolSize"&gt;${hibernate.c3p0.maxPoolSize}&lt;/prop&gt;<br />    &lt;prop key="hc3p0.timeout"&gt;${hibernate.c3p0.timeout}&lt;/prop&gt;<br />    &lt;prop key="c3p0.max_statement"&gt;${hibernate.c3p0.max_statement}&lt;/prop&gt;<br />    &lt;prop key="user"&gt;${jdbc.username}&lt;/prop&gt;<br />    &lt;prop key="password"&gt;${jdbc.password}&lt;/prop&gt;<br />    &lt;prop key="c3p0.testConnectionOnCheckout"&gt;true&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><font color="#006400">#Jdbc Configuration</font></p>
		<p>jdbc.driver=com.mysql.jdbc.Driver<br />jdbc.url=jdbc:mysql://localhost/wsh?useUnicode=true&amp;characterEncoding=utf-8<br />jdbc.username=wsh<br />jdbc.password=wsh</p>
		<p>hibernate.c3p0.minPoolSize=2<br />hibernate.c3p0.maxPoolSize=10<br />hibernate.c3p0.timeout=100<br />hibernate.c3p0.max_statement=900<br /><br />注:当然还有很多例如"<font color="#800080">org.apache.commons.dbcp.BasicDataSource</font><font color="#000000">"<br />&lt;bean id="dataSource"<br />  class="org.apache.commons.dbcp.BasicDataSource"<br />  destroy-method="close"&gt;<br />  &lt;property name="driverClassName"<br />   value="${jdbc.driverClassName}" /&gt;<br />  &lt;property name="url" value="${jdbc.url}" /&gt;<br />  &lt;property name="username" value="${jdbc.username}" /&gt;<br />  &lt;property name="password" value="${jdbc.password}" /&gt;<br /> &lt;/bean&gt;<br />jdbc.driverClassName=org.gjt.mm.mysql.Driver<br />jdbc.url=jdbc:mysql://172.19.30.178:3306/wsh?useUnicode=true&amp;characterEncoding=utf-8<br />jdbc.username=wsh<br />jdbc.password=wsh<br /></font><font color="#000000"><br />hibernate.dialect=org.hibernate.dialect.MySQLDialect<br />hibernate.show_sql=true<br />hibernate.hbm2ddl.auto=update<br /><br /><strong>3.sessionFactory配置<br /></strong>&lt;bean id="sessionFactory"<br />  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;<br />  &lt;property name="<font color="#006400">dataSource</font>" ref="dataSource" /&gt;</font></p>
		<p>
				<font color="#000000">  &lt;property name="<font color="#006400">mappingDirectoryLocations</font>"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;<font color="#800080">classpath:/com/rain/wsh/model/</font>&lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;</font>
		</p>
		<p>
				<font color="#000000">  &lt;property name="<font color="#006400">hibernateProperties</font>"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="<font color="#006400">hibernate.dialect</font>"&gt;<br />     org.hibernate.dialect.MySQLDialect<br />    &lt;/prop&gt;<br />    &lt;prop key="<font color="#006400">hibernate.show_sql</font>"&gt;false&lt;/prop&gt;<br />    &lt;!-- &lt;prop key="hibernate.cache.use_query_cache"&gt;false&lt;/prop&gt; --&gt;<br />    &lt;!-- prop key="hibernate.query.factory_class"&gt;org.hibernate.hql.classic.ClassicQueryTranslatorFactory&lt;/prop--&gt;<br />    &lt;prop key="hibernate.connection.provider_class"&gt;<br />     org.hibernate.connection.C3P0ConnectionProvider<br />    &lt;/prop&gt;<br />    &lt;prop key="hibernate.generate_statistics"&gt;false&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br />&lt;bean id="sessionFactory"<br />  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"<br />  singleton="true"&gt;<br />  &lt;property name="dataSource"&gt;<br />   &lt;ref local="dataSource" /&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#006400">mappingResources</font>"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;<br />     com/rain/study/model/User.hbm.xml<br />    &lt;/value&gt;<br />   &lt;/list&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#006400">hibernateProperties</font>"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="hibernate.dialect"&gt;<br />     ${hibernate.dialect}<br />    &lt;/prop&gt;<br />    &lt;prop key="hibernate.show_sql"&gt;<br />     ${hibernate.show_sql}<br />    &lt;/prop&gt;<br />    &lt;!--   &lt;prop key="hibernate.hbm2ddl.auto"&gt;${hibernate.hbm2ddl.auto}&lt;/prop&gt;--&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>4.transactionManager配置</strong><br />&lt;!-- Hibernate transaction processing --&gt;<br /> &lt;bean id="transactionManager"<br />  class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;<br />  &lt;property name="sessionFactory"&gt;<br />   &lt;ref local="sessionFactory" /&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /><br /><strong>5.baseTxService配置(Service的代理工厂)</strong><br />&lt;bean id="baseTxService" abstract="true"<br />  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;<br />  &lt;property name="<font color="#006400">transactionManager</font>" ref="transactionManager" /&gt;<br />  &lt;property name="<font color="#006400">transactionAttributes</font>"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="create*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="delete*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="get*"&gt;PROPAGATION_REQUIRED, readOnly&lt;/prop&gt;<br />    &lt;prop key="*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br />  &lt;property name="postInterceptors" ref="<font style="BACKGROUND-COLOR: #800080">methodSecurityInterceptor</font>" /&gt;<br /> &lt;/bean&gt;<br /></font>
				<font style="BACKGROUND-COLOR: #ffffff" color="#800080">methodSecurityInterceptor则是acegi中的拦截器(<font color="#006400">注:见下一篇acegi配置</font>)<br /><br /><font color="#000000"><strong>6.Service配置<br /></strong>&lt;bean id="userService" parent="<font color="#006400">baseTxService</font>"&gt;<br />    &lt;property name="<font color="#006400">target</font>"&gt;<br />      &lt;bean class="com.rain.wsh.service.impl.UserServiceImpl"/&gt;<br />    &lt;/property&gt;<br />&lt;/bean&gt;<br /><br />注意:为了更加的是配置文件清晰,可以把spring的配置文件分成多个配置文件,例如(applicationContext-hibernate.xml,applicationContext-service.xml等),然后在web.xml中配置的时候写成:<br /><font color="#006400"> &lt;context-param&gt;<br />        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br />        &lt;param-value&gt;/WEB-INF/applicationContext*.xml&lt;/param-value&gt;<br /> &lt;/context-param&gt;</font><br /><br /></font><br /></font>
		</p><img src ="http://www.blogjava.net/rain1102/aggbug/107136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2007-03-29 10:10 <a href="http://www.blogjava.net/rain1102/articles/107136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Spring] AOP中的术语</title><link>http://www.blogjava.net/rain1102/articles/90241.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Wed, 27 Dec 2006 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/90241.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/90241.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/90241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/90241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/90241.html</trackback:ping><description><![CDATA[<p>英文原文出自《Spring In Action》</p>
		<p>像绝大多数的技术一样，AOP也有自己的术语。不幸的是，很多用于描述AOP特征的术语并不直观，但是，它们已经成为了AOP语言的一部分，如果你想理解AOP，你必须学会这门AOP语言。通俗地说，你想在圈子里面混，你就得学会说行话。</p>
		<p>
				<strong>Aspect</strong>
		</p>
		<p>Aspect是你正在实现的一个<a href="http://en.wikipedia.org/wiki/Cross_cutting_%28programming%29"><font color="#333333">cross-cutting</font></a>的功能，它是你应用中正在模块化的一个方面（aspect）。比较通用的一个例子是日志。记录日志是一项贯穿整个应用的服务。由于应用基本以功能（基于业务逻辑）为界限进行划分模块，故通过继承的方法来重用日志模块似乎不合理。但是，你可以创建一个日志aspect来实现你的想法。</p>
		<p>
				<strong>Joinpoint</strong>
		</p>
		<p>Joinpoint是在应用运行中那些aspect可以插进来的点。这个点可能是一个被调用的方法，一个被抛出的异常，甚至可以是一个被改变的字段。在这些点处添加你的aspect的代码，就可以为你的应用增加一些新的行为。</p>
		<p>
				<strong>Advice</strong>
		</p>
		<p>Advice是对aspect的一个具体实现。它向系统建议（advice）增加一个新的行为。在我们的日志例子中，日志advice包含了记录日志的代码并实现真正的日志记录，比如将日志写入文件。Advice被添加到joinpoint点上。</p>
		<p>
				<strong>Pointcut</strong>
		</p>
		<p>Pointcut定义了advice应该被插入到什么样的joinpoint点上。Advice可以被应用到任意AOP框架支持的joinpoint上。当然，你不会希望将所有的aspect应用到可以被应用的joinpoint上面。Pointcut让你可以指定advice应用的位置。通常，你用具体的类名或方法名，或者一些符合表达式的类或方法名来指定pointcut。 一些AOP框架允许你创建动态的pointcuts，这些pointcuts可以在运行的时候动态决定是否需要应用advice，比如方法的参数值。</p>
		<p>
				<strong>Introduction</strong>
		</p>
		<p>Introduction可以让你添加方法和属性到已经存在的类中。例如，你可以创建一个Auditable的advice类用来跟踪某对象最后改变的时期。这个可以简单地通过一个属性记录状态，并添加一个setLastModified(Date)方法来实现。然后，它可以被引入（introduce）到已经存在的类。这样，已有的类不需要做任何改变就有了个新的功能。</p>
		<p>
				<strong>Target</strong>
		</p>
		<p>Target是正在被advice的类，这可以是你自己写的一个类或者是你想增加新的功能的第三方提供的类。没有AOP，这个类必须被包括自身主要的逻辑并且额外加上那些<a href="http://en.wikipedia.org/wiki/Cross_cutting_%28programming%29"><font color="#333333">cross-cutting</font></a>关心的逻辑。有了AOP，target类只需要关注自身所需要关心的，而把那些应用于自身的advices抛到脑后。</p>
		<p>
				<strong>Proxy</strong>
		</p>
		<p>Proxy是被应用了advice的target实例。从客户实例的角度来看，无论是target实例（AOP之前）还是proxy实例（AOP以后），都是一样的，当然，它们本来就应该是一样的。也就是说，你的既有应用不需要做改变来支持proxy类。</p>
		<p>
				<strong>Weaving</strong>
		</p>
		<p>Weaving是指把aspects应用到目标实例上去创建一个新的proxied实例的过程。Aspects在目标对象的joinpoint被组合（weave）进去。Weaving可以发生在目标类生存的如下时间：</p>
		<ul>
				<li>编译期 -- Aspects在目标类编译期被weave。这个需要特殊的编译器。 
</li>
				<li>载入期 -- Aspects在目标类载入期被weave。这个需要特殊的类装载器。 
</li>
				<li>运行期 -- Aspects在应用运行时的某个时期被weave。一般来说，AOP容器在weave in aspects的时候会动态创建proxy类来代理target类。</li>
		</ul>
		<p>图例：</p>
		<p>
				<img alt="" src="http://blog.donews.com/images/blog_donews_com/vincentcao/88361/o_aopterm.JPG" />
		</p>
		<p>
		</p>
		<p>PS: </p>
		<br />
		<br />
		<p id="TBPingURL">Trackback: http://tb.donews.net/TrackBack.aspx?PostId=697258</p><img src ="http://www.blogjava.net/rain1102/aggbug/90241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-27 10:51 <a href="http://www.blogjava.net/rain1102/articles/90241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi工作流程</title><link>http://www.blogjava.net/rain1102/articles/89016.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Wed, 20 Dec 2006 04:51:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/89016.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/89016.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/89016.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/89016.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/89016.html</trackback:ping><description><![CDATA[<div id="topict">Acegi工作流程</div>
		<div class="logt" style="OVERFLOW: hidden; WIDTH: 100%">
				<p>
						<span style="FONT-SIZE: 10pt">任何一个安全系统都包括authentication和authorization两部分，Acegi相同。</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">
								<strong>第一部分：authentication</strong>
						</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">1、acegi通过AuthenticationProcessingFilter拦截login请求获取Principal和Credential信息（通俗一点就是用户名和密码）；</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">2、验证用户名密码，由这个Filter调用认证管理器AuthenticatiomManager进行验证。</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">AuthenticatiomManager本身并不具备验证的功能，它相当与是一个验证控制器，由它来管理验证的过程及方式。AuthenticatiomManager是通过调用provider来进行验证的，一个manager中可以具有多个provider，但只要有一个provider验证通过，manager就认为验证成功。</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">这部分要明白三点：一，provider是可以配置进去的，因为acegi是基于spring的；二是AuthenticatiomManager是可以被重写的，你可以将manager改成你自己希望的控制器；三，好好利用event，这是标准的observer模式。acegi中的设计模式研究将在以后的贴子中讨论。</span>
				</p>
				<p>
						<span style="FONT-SIZE: 10pt">3、provider进行验证。</span>
				</p>
		</div>
		<p>
				<span style="FONT-SIZE: 10pt">provider是真正的验证模块，并且决定了验证的模式。provider目前acegi提供了dao、jaas，cas，x509，ldap等几种验证方式，这些验证方式的具体内容可以查阅acegi的文档。provider验证通过后将Authentication对象返回。</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">4、AuthenticationProcessingFilter将对象保存到ContextHolder中。Authentication部分结束。</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">
						<strong>第二部分：authorization</strong>
				</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">1、用户提交请求，拦截器FilterSecurityInterceptor拦截请求，拦截器是一个Filter.</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">2 、鉴权，拦截器调用AccessDecisionManager进行鉴权。</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">AccessDecisionManager是通过投票的方式来决定是否有权限访问资源。所谓投票就要包括投票的参与者和投票的策略。</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">投票的参与者decisionVoters，这是AccessDecisionManager的一个属性。decisionVoter能从某一个角度决定用户是否能访问资源，例如RoleVoter来判断用户的角色是否有权限访问资源，MaxuserVoter来决定某个资源的访问用户数是否已经达到了最大值等。</span>
		</p>
		<p>
				<span style="FONT-SIZE: 10pt">投票策略。投票的策略是通过不同的AccessDecisionManager来实现的，例如acegi提供的AffirmativeBased对象，这个对象的策略就是只要有一个投票通过就全体通过。UnanimousBased对象的策略是必须全体投票通过才能通过。但在大多数情况下acegi提供的AccessDecisionManager不能满足我们的要求，这就需要我们去实现AccessDecisionManager接口，去定制适合自己项目的策略。</span>
		</p>
		<div>
				<span style="FONT-SIZE: 10pt">3、投票。投票对象必须实现AccessDecisionVoter接口。投票对象关注的是某一方面的决定权，如果投票通过则Vote方法来完成的。vote方法必须返回一个int型的数据代表投票结果，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。</span>
		</div>
		<div>
				<span style="FONT-SIZE: 10pt">
				</span> </div>
		<div>
				<span style="FONT-SIZE: 10pt">
						<h4>
								<span style="FONT-SIZE: 10pt">安全拦截器</span>
						</h4>
						<h5>  拦截器如何工作<br />  MethodInvocation拦截器<br />  FilterInvocation拦截器</h5>
						<h4>
								<span style="FONT-SIZE: 10pt">认证</span>
						</h4>
						<h5>  认证请求<br />  认证管理器<br />  Authentication Provider</h5>
						<h4>
								<span style="FONT-SIZE: 10pt">授权</span>
						</h4>
						<h5>  Access Decision Manager<br />  Voting Decision Manager<br />  授权管理推荐</h5>
						<h4>
								<span style="FONT-SIZE: 10pt">ContextHolder的用户接口</span>
						</h4>
						<h5>  用户接口目标<br />  HTTP会话认证<br />  HTTP Basic认证</h5>
				</span>
		</div><img src ="http://www.blogjava.net/rain1102/aggbug/89016.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-20 12:51 <a href="http://www.blogjava.net/rain1102/articles/89016.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi安全系统的配置</title><link>http://www.blogjava.net/rain1102/articles/88869.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 19 Dec 2006 10:35:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/88869.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/88869.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/88869.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/88869.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/88869.html</trackback:ping><description><![CDATA[Acegi 的配置看起来非常复杂,但事实上在实际项目的安全应用中我们并不需要那么多功能,清楚的了解Acegi配置中各项的功能，有助于我们灵活的运用Acegi于实践中。
<h2>2.1 在Web.xml中的配置</h2><p>1)  <strong>FilterToBeanProxy</strong><br />　　Acegi通过实现了Filter接口的FilterToBeanProxy提供一种特殊的使用Servlet Filter的方式，它委托Spring中的Bean -- FilterChainProxy来完成过滤功能，这好处是简化了web.xml的配置，并且充分利用了Spring IOC的优势。FilterChainProxy包含了处理认证过程的filter列表，每个filter都有各自的功能。</p><pre>    &lt;filter&gt;<br />        &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />        &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />        &lt;init-param&gt;<br />            &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />            &lt;param-value&gt;org.acegisecurity.util.FilterChainProxy&lt;/param-value&gt;<br />        &lt;/init-param&gt;<br />    &lt;/filter&gt;</pre><p>2) <strong>filter-mapping</strong><br />　　&lt;filter-mapping&gt;限定了FilterToBeanProxy的URL匹配模式,只有*.do和*.jsp和/j_acegi_security_check 的请求才会受到权限控制，对javascript,css等不限制。</p><pre>   &lt;filter-mapping&gt;<br />      &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />      &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;<br />    &lt;/filter-mapping&gt;<br />    <br />    &lt;filter-mapping&gt;<br />      &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />      &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />    &lt;/filter-mapping&gt;<br />    <br />    &lt;filter-mapping&gt;<br />      &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />      &lt;url-pattern&gt;/j_acegi_security_check&lt;/url-pattern&gt;<br />    &lt;/filter-mapping&gt;</pre><p>3) <strong>HttpSessionEventPublisher</strong><br />　　&lt;listener&gt;的HttpSessionEventPublisher用于发布HttpSessionApplicationEvents和HttpSessionDestroyedEvent事件给spring的applicationcontext。</p><pre>    &lt;listener&gt;<br />        &lt;listener-class&gt;org.acegisecurity.ui.session.HttpSessionEventPublisher&lt;/listener-class&gt;<br />    &lt;/listener&gt;<br /></pre><h2><br />2.2 在applicationContext-acegi-security.xml中</h2><h3>2.2.1 FILTER CHAIN</h3><p>　　FilterChainProxy会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写， PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式 </p><pre>    &lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt;<br />        &lt;property name="filterInvocationDefinitionSource"&gt;<br />            &lt;value&gt;<br />                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />                PATTERN_TYPE_APACHE_ANT<br />               /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,<br />basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,<br /> exceptionTranslationFilter,filterInvocationInterceptor<br />            &lt;/value&gt;<br />        &lt;/property&gt;<br />    &lt;/bean&gt;</pre><h3>2.2.2 基础认证</h3><p>1) <strong>authenticationManager</strong><br />　　起到认证管理的作用，它将验证的功能委托给多个Provider，并通过遍历Providers, 以保证获取不同来源的身份认证，若某个Provider能成功确认当前用户的身份，authenticate()方法会返回一个完整的包含用户授权信息的Authentication对象，否则会抛出一个AuthenticationException。<br />Acegi提供了不同的AuthenticationProvider的实现,如：<br />        DaoAuthenticationProvider 从数据库中读取用户信息验证身份<br />        AnonymousAuthenticationProvider 匿名用户身份认证<br />        RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证<br />        AuthByAdapterProvider 使用容器的适配器验证身份<br />        CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆<br />        JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份<br />        RemoteAuthenticationProvider 根据远程服务验证用户身份<br />        RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证<br />        X509AuthenticationProvider 从X509认证中获取用户信息验证身份<br />        TestingAuthenticationProvider 单元测试时使用</p><p>        每个认证者会对自己指定的证明信息进行认证，如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。</p><pre>&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;<br />        &lt;property name="providers"&gt;<br />            &lt;list&gt;<br />                &lt;ref local="daoAuthenticationProvider"/&gt;<br />                &lt;ref local="anonymousAuthenticationProvider"/&gt;<br />                &lt;ref local="rememberMeAuthenticationProvider"/&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />&lt;/bean&gt;</pre><p><br />2) <strong>daoAuthenticationProvider</strong><br />　　进行简单的基于数据库的身份验证。DaoAuthenticationProvider获取数据库中的账号密码并进行匹配，若成功则在通过用户身份的同时返回一个包含授权信息的Authentication对象，否则身份验证失败，抛出一个AuthenticatiionException。</p><pre>    &lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />        &lt;property name="userDetailsService" ref="jdbcDaoImpl"/&gt;<br />        &lt;property name="userCache" ref="userCache"/&gt;<br />        &lt;property name="passwordEncoder" ref="passwordEncoder"/&gt;<br />   &lt;/bean&gt;</pre><p><br />3) <strong>passwordEncoder</strong><br />　　使用加密器对用户输入的明文进行加密。Acegi提供了三种加密器:<br />PlaintextPasswordEncoder—默认，不加密，返回明文.<br />ShaPasswordEncoder—哈希算法(SHA)加密<br />Md5PasswordEncoder—消息摘要(MD5)加密</p><pre>&lt;bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/&gt;</pre><p><br />4) <strong>jdbcDaoImpl</strong><br />　　用于在数据中获取用户信息。 acegi提供了用户及授权的表结构，但是您也可以自己来实现。通过usersByUsernameQuery这个SQL得到你的(用户ID,密码,状态信息);通过authoritiesByUsernameQuery这个SQL得到你的(用户ID,授权信息)</p><pre> 
&lt;bean id="jdbcDaoImpl" 
class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"&gt;<br />        
&lt;property name="dataSource" 
ref="dataSource"/&gt;<br />        &lt;property 
name="usersByUsernameQuery"&gt;<br />            
&lt;value&gt;select loginid,passwd,1 from users where loginid = 
?&lt;/value&gt;<br />        
&lt;/property&gt;<br />        &lt;property 
name="authoritiesByUsernameQuery"&gt;<br />            
&lt;value&gt;select u.loginid,p.name from users u,roles r,permissions 
p,user_role ur,role_permis rp where u.id=ur.user_id and r.id=ur.role_id and 
p.id=rp.permis_id 
and<br />                
r.id=rp.role_id and p.status='1' and 
u.loginid=?&lt;/value&gt;<br />        
&lt;/property&gt;<br />&lt;/bean&gt;</pre><p>5) <strong>userCache　&amp;  resourceCache</strong><br />　　缓存用户和资源相对应的权限信息。每当请求一个受保护资源时，daoAuthenticationProvider就会被调用以获取用户授权信息。如果每次都从数据库获取的话，那代价很高，对于不常改变的用户和资源信息来说，最好是把相关授权信息缓存起来。(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a> )<br />userCache提供了两种实现: NullUserCache和EhCacheBasedUserCache, NullUserCache实际上就是不进行任何缓存，EhCacheBasedUserCache是使用Ehcache来实现缓功能。</p><pre>    &lt;bean id="userCacheBackend" 
class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />        
&lt;property name="cacheManager" 
ref="cacheManager"/&gt;<br />        
&lt;property name="cacheName" value="userCache"/&gt;<br />    &lt;/bean&gt;<br />    &lt;bean id="userCache" 
class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" 
autowire="byName"&gt;<br />        &lt;property 
name="cache" ref="userCacheBackend"/&gt;<br />      
&lt;/bean&gt;<br />    &lt;bean id="resourceCacheBackend" 
class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />        
&lt;property name="cacheManager" 
ref="cacheManager"/&gt;<br />        
&lt;property name="cacheName" value="resourceCache"/&gt;<br />    &lt;/bean&gt;<br />    &lt;bean id="resourceCache" 
class="org.springside.modules.security.service.acegi.cache.ResourceCache" 
autowire="byName"&gt;<br />        &lt;property 
name="cache" ref="resourceCacheBackend"/&gt;<br />    &lt;/bean&gt;</pre><p><br />6) <strong>basicProcessingFilter</strong><br />　　用于处理HTTP头的认证信息，如从Spring远程协议(如Hessian和Burlap)或普通的浏览器如IE,Navigator的HTTP头中获取用户信息，将他们转交给通过authenticationManager属性装配的认证管理器。如果认证成功，会将一个Authentication对象放到会话中，否则，如果认证失败，会将控制转交给认证入口点(通过authenticationEntryPoint属性装配)</p><pre>    &lt;bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"&gt;<br />        &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />        &lt;property name="authenticationEntryPoint" ref="basicProcessingFilterEntryPoint"/&gt;<br />    &lt;/bean&gt;</pre><p>7) <strong>basicProcessingFilterEntryPoint</strong><br />　　通过向浏览器发送一个HTTP401(未授权)消息，提示用户登录。<br />处理基于HTTP的授权过程， 在当验证过程出现异常后的"去向"，通常实现转向、在response里加入error信息等功能。</p><pre> &lt;bean 
id="basicProcessingFilterEntryPoint" 
class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"&gt;<br />        
&lt;property name="realmName" value="SpringSide Realm"/&gt;<br />&lt;/bean&gt;</pre><p>8) <strong>authenticationProcessingFilterEntryPoint</strong><br />　　当抛出AccessDeniedException时，将用户重定向到登录界面。属性loginFormUrl配置了一个登录表单的URL,当需要用户登录时，authenticationProcessingFilterEntryPoint会将用户重定向到该URL</p><pre> 
&lt;bean id="authenticationProcessingFilterEntryPoint" 
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;<br />        
&lt;property 
name="loginFormUrl"&gt;<br />            
&lt;value&gt;/security/login.jsp&lt;/value&gt;<br />        
&lt;/property&gt;<br />        &lt;property 
name="forceHttps" value="false"/&gt;<br />&lt;/bean&gt;</pre><h2>2.2.3 HTTP安全请求</h2><p>1) <strong>httpSessionContextIntegrationFilter</strong><br />　　每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象，在request完后, 又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用，使之能跨越多个请求。</p><pre>&lt;bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"&gt;&lt;/bean&gt;<br />    &lt;bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />        &lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />        &lt;property name="decisionVoters"&gt;<br />            &lt;list&gt;<br />                &lt;ref bean="roleVoter"/&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />&lt;/bean&gt;</pre><p><br />2) <strong>httpRequestAccessDecisionManager</strong><br />　　经过投票机制来决定是否可以访问某一资源(URL或方法)。allowIfAllAbstainDecisions为false时如果有一个或以上的decisionVoters投票通过,则授权通过。可选的决策机制有ConsensusBased和UnanimousBased</p><pre>    &lt;bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />        &lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />        &lt;property name="decisionVoters"&gt;<br />            &lt;list&gt;<br />                &lt;ref bean="roleVoter"/&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />    &lt;/bean&gt;</pre><p><br />3) <strong>roleVoter</strong><br /> 　　必须是以rolePrefix设定的value开头的权限才能进行投票,如AUTH_ , ROLE_</p><pre>    &lt;bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"&gt;<br />        &lt;property name="rolePrefix" value="AUTH_"/&gt;<br />   &lt;/bean&gt;</pre><p>4）<strong>exceptionTranslationFilter</strong><br />　　异常转换过滤器，主要是处理AccessDeniedException和AuthenticationException，将给每个异常找到合适的"去向" </p><pre>   &lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;<br />        &lt;property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/&gt;<br />    &lt;/bean&gt;</pre><p>5) <strong>authenticationProcessingFilter</strong><br />　　和servlet spec差不多,处理登陆请求.当身份验证成功时，AuthenticationProcessingFilter会在会话中放置一个Authentication对象，并且重定向到登录成功页面<br />         authenticationFailureUrl定义登陆失败时转向的页面<br />         defaultTargetUrl定义登陆成功时转向的页面<br />         filterProcessesUrl定义登陆请求的页面<br />         rememberMeServices用于在验证成功后添加cookie信息</p><pre>    &lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />        &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />        &lt;property name="authenticationFailureUrl"&gt;<br />            &lt;value&gt;/security/login.jsp?login_error=1&lt;/value&gt;<br />        &lt;/property&gt;<br />        &lt;property name="defaultTargetUrl"&gt;<br />            &lt;value&gt;/admin/index.jsp&lt;/value&gt;<br />        &lt;/property&gt;<br />        &lt;property name="filterProcessesUrl"&gt;<br />            &lt;value&gt;/j_acegi_security_check&lt;/value&gt;<br />        &lt;/property&gt;<br />        &lt;property name="rememberMeServices" ref="rememberMeServices"/&gt;<br />    &lt;/bean&gt;</pre><p>6) <strong>filterInvocationInterceptor</strong><br />　　在执行转向url前检查objectDefinitionSource中设定的用户权限信息。首先，objectDefinitionSource中定义了访问URL需要的属性信息(这里的属性信息仅仅是标志，告诉accessDecisionManager要用哪些voter来投票)。然后，authenticationManager掉用自己的provider来对用户的认证信息进行校验。最后，有投票者根据用户持有认证和访问url需要的属性，调用自己的voter来投票，决定是否允许访问。</p><pre>    &lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />        &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />        &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />        &lt;property name="objectDefinitionSource" ref="filterDefinitionSource"/&gt;<br />    &lt;/bean&gt;</pre><p><br />7) <strong>filterDefinitionSource </strong>(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a>)<br />　　自定义DBFilterInvocationDefinitionSource从数据库和cache中读取保护资源及其需要的访问权限信息 </p><pre>&lt;bean id="filterDefinitionSource" class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource"&gt;<br />        &lt;property name="convertUrlToLowercaseBeforeComparison" value="true"/&gt;<br />        &lt;property name="useAntPath" value="true"/&gt;<br />        &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />&lt;/bean&gt;</pre><h2>2.2.4 方法调用安全控制</h2><p>(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a>)</p><p>1) methodSecurityInterceptor<br />　　在执行方法前进行拦截，检查用户权限信息<br />2) methodDefinitionSource<br />　　自定义MethodDefinitionSource从cache中读取权限</p><pre>   &lt;bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />        &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />        &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />        &lt;property name="objectDefinitionSource" ref="methodDefinitionSource"/&gt;<br />    &lt;/bean&gt;<br />    &lt;bean id="methodDefinitionSource" class="org.springside.modules.security.service.acegi.DBMethodDefinitionSource"&gt;<br />        &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />    &lt;/bean&gt;</pre><h2>2.3 Jcaptcha验证码</h2><p>采用 <a href="http://jcaptcha.sourceforge.net/">http://jcaptcha.sourceforge.net</a> 作为通用的验证码方案，请参考SpringSide中的例子，或网上的：<br /><a href="http://www.coachthrasher.com/page/blog?entry=jcaptcha_with_appfuse">http://www.coachthrasher.com/page/blog?entry=jcaptcha_with_appfuse</a>。</p><p>差沙在此过程中又发现acegi logout filter的错误，进行了修正。</p><p>另外它默认提供的图片比较难认，我们custom了一个美观一点的版本。</p><img src ="http://www.blogjava.net/rain1102/aggbug/88869.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-19 18:35 <a href="http://www.blogjava.net/rain1102/articles/88869.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi简介</title><link>http://www.blogjava.net/rain1102/articles/88847.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 19 Dec 2006 08:40:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/88847.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/88847.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/88847.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/88847.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/88847.html</trackback:ping><description><![CDATA[Acegi安全系统，是一个用于Spring Framework的安全框架，能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务，包括使用Bean Context，拦截器和面向接口的编程方式。因此，Acegi安全系统能够轻松地适用于复杂的安全需求。<br />       安全涉及到两个不同的概念，认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。<br />       在Acegi安全系统中，需要被认证的用户，系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同，它并没有角色和用户组的概念。<br />Acegi系统设计<br />  关键组件<br />      Acegi安全系统包含以下七个关键的功能组件：<br />        1 Authentication对象，包含了Principal，Credential和Principal的授权信息。同时还可以包含关于发起认证请求的客户的其他信息，如IP地址。<br />        2 ContextHolder对象，使用ThreadLocal储存Authentication对象的地方。<br />        3 AuthenticationManager，用于认证ContextHolder中的Authentication对象。<br />        4 AccessDecissionManager，用于授权一个特定的操作。<br />        5 RunAsManager，当执行特定的操作时，用于选择性地替换Authentication对象。<br />        6 Secure Object拦截器，用于协调AuthenticationManager，AccessDecissionManager，RunAsManager和特定操作的执行。<br />        7 ObjectDefinitionSource，包含了特定操作的授权定义。<br />      这七个关键的功能组件的关系如下图所示（图中灰色部分是关键组件）：<br /><br /><br /><strong>安全管理对象</strong><br />       Acegi安全系统目前支持两类安全管理对象。<br />       第一类的安全管理对象管理AOP Alliance的MethodInvocation，开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为MethodInvocation来使用，Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理，就像在Spring的事务管理一样使用。<br />       第二类是FilterInvocation。它用过滤器（Filter）来创建，并简单地包装了HTTP的ServletRequest，ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常，开发人员并不需要了解它的工作机制，因为他们只需要将Filter加入web.xml，Acegi安全系统就可以工作了。<br /><br /><strong>安全配置参数</strong><br />       每个安全管理对象都可以描述数量不限的各种安全认证请求。例如，MethodInvocation对象可以描述带有任意参数的任意方法的调用，而FilterInvocation可以描述任意的HTTP URL。<br />       Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如，对于BankManager.getBalance（int accountNumber）方法和BankManager.approveLoan（int applicationNumber）方法，它们需要的认证请求的安全配置很不相同。<br />       为了保存不同的认证请求的安全配置，需要使用配置参数。从实现的视角来看，配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现，SecurityConfig，它把配置参数保存为一个字符串。<br />       ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器，它保存了和特定请求相关的ConfigAttribute的集合。<br />       当安全拦截器收到一个安全认证请求时，需要决定应用哪一个配置参数。换句话说，它需要找出应用于这个请求的ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是public ConfigAttributeDefinition getAttributes(Object object)，其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息，所以ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息，以查找相关的ConfigAttributeDefiniton对象。<br /><br /><br /><strong>Acegi如何工作</strong><br />       为了说明Acegi安全系统如何工作，我们设想一个使用Acegi的例子。通常，一个安全系统需要发挥作用，它必须完成以下的工作：<br />      1 首先，系统从客户端请求中获得Principal和Credential；<br />      2 然后系统认证Principal和Credential信息；<br />      3 如果认证通过，系统取出Principal的授权信息；<br />      4 接下来，客户端发起操作请求；<br />      5 系统根据预先配置的参数检查Principal对于该操作的授权；<br />      6 如果授权检查通过则执行操作，否则拒绝。<br />      那么，Acegi安全系统是如何完成这些工作的呢？首先，我们来看看Acegi安全系统的认证和授权的相关类： <br />      安全拦截器的抽象基类，它包含有两个管理类，AuthenticationManager和AccessDecisionManager。AuthenticationManager用于认证ContextHolder中的Authentication对象（包含了Principal，Credential和Principal的授权信息）；AccessDecissionManager则用于授权一个特定的操作。<br /><br />      下面来看一个MethodSecurityInterceptor的例子：<br /><pre class="overflow">      &lt;bean id="bankManagerSecurity" <br />                     class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor"&gt;<br />             &lt;property name="validateConfigAttributes"&gt;<br />                    &lt;value&gt;true&lt;/value&gt;<br />            &lt;/property&gt;<br />            &lt;property name="authenticationManager"&gt;<br />                   &lt;ref bean="authenticationManager"/&gt;<br />            &lt;/property&gt;<br />            &lt;property name="accessDecisionManager"&gt;<br />                  &lt;ref bean="accessDecisionManager"/&gt;<br />            &lt;/property&gt;<br />            &lt;property name="objectDefinitionSource"&gt;<br />                  &lt;value&gt;<br />                     net.sf.acegisecurity.context.BankManager.delete*=<br />                             ROLE_SUPERVISOR,RUN_AS_SERVER<br />                     net.sf.acegisecurity.context.BankManager.getBalance=<br />                             ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_<br />                  &lt;/value&gt;<br />            &lt;/property&gt;<br />      &lt;/bean&gt; </pre><br />      上面的配置文件中，MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器，authenticationManager和accessDecisionManager。这两者的配置如下：<br />      <pre class="overflow">&lt;bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br />               &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="daoAuthenticationProvider" <br />                     class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />               &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br />               &lt;property name="providers"&gt;<br />                      &lt;list&gt;&lt;ref bean="daoAuthenticationProvider"/&gt;&lt;/list&gt;<br />               &lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;<br />      &lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br />               &lt;property name="allowIfAllAbstainDecisions"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br />               &lt;property name="decisionVoters"&gt;<br />                      &lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br />               &lt;/property&gt;<br />      &lt;/bean&gt;</pre><br /><br />       准备工作做好了，现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用为例子，它包括下面的步骤：<br />       1. 用户登录系统，Acegi从acegisecurity.ui子系统的安全拦截器（如BasicProcessingFilter）中得到用户的登录信息（包括Principal和Credential）并放入Authentication对象，并保存在ContextHolder对象中；<br />       2. 安全拦截器将Authentication对象交给AuthenticationManager进行身份认证，如果认证通过，返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息；<br />       3. 用户登录成功后，继续进行业务操作；<br />       4. 安全拦截器（bankManagerSecurity）收到客户端操作请求后，将操作请求的数据包装成安全管理对象（FilterInvocation或MethodInvocation对象）；<br />       5. 然后，从配置文件（ObjectDefinitionSource）中读出相关的安全配置参数ConfigAttributeDefinition；<br />       6. 接着，安全拦截器取出ContextHolder中的Authentication对象，把它传递给AuthenticationManager进行身份认证，并用返回值更新ContextHolder的Authentication对象；<br />       7. 将Authentication对象，ConfigAttributeDefinition对象和安全管理对象（secure Object）交给AccessDecisionManager，检查Principal的操作授权；<br />       8. 如果授权检查通过则执行客户端请求的操作，否则拒绝；<br /><br /><strong>AccessDecisionVoter</strong><br />       注意上节的accessDecisionManager是一个AffirmativeBased类，它对于用户授权的投票策略是，只要通过其中的一个授权投票检查，即可通过；它的allowIfAllAbstainDecisions属性值是false，意思是如果所有的授权投票是都是弃权，则通不过授权检查。<br />       Acegi安全系统包括了几个基于投票策略的AccessDecisionManager，上节的RoleVoter就是其中的一个投票策略实现，它是AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策，AccessDecisionManager则根据投票结果来决定是通过授权检查，还是抛出AccessDeniedException例外。<br />       AccessDecisionVoter接口共有三个方法：<br />public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);<br />public boolean supports(ConfigAttribute attribute);<br />public boolean supports(Class clazz);<br />       其中的vote方法返回int返回值，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。<br />       Acegi安全系统中，使用投票策略的AccessDecisionManager共有三个具体实现类：AffirmativeBased、ConsensusBased和UnanimousBased。它们的投票策略是，AffirmativeBased类只需有一个投票赞成即可通过；ConsensusBased类需要大多数投票赞成即可通过；而UnanimousBased类需要所有的投票赞成才能通过。<br />       RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开头，RoleVoter则进行投票。如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_开头的ConfigAttribute，则投票通过，否则不通过。如果没有以ROLE_开头的ConfigAttribute，RoleVoter则弃权。<br /><br /><strong>安全拦截器</strong><br />  拦截器如何工作<br />  MethodInvocation拦截器<br />  FilterInvocation拦截器<br />认证<br />  认证请求<br />  认证管理器<br />  Authentication Provider<br />授权<br />  Access Decision Manager<br />  Voting Decision Manager<br />  授权管理推荐<br />ContextHolder的用户接口<br />  用户接口目标<br />  HTTP会话认证<br />  HTTP Basic认证<br /><br />1、Log4j的概念<br />   Log4j中有三个主要的组件，它们分别是Logger、Appender和Layout，Log4j 允许开发人员定义多个Logger，每个Logger拥有自己的名字，Logger之间通过名字来表明隶属关系。有一个Logger称为Root，它永远 存在，且不能通过名字检索或引用，可以通过Logger.getRootLogger()方法获得，其它Logger通过 Logger.getLogger(String name)方法。<br />   Appender则是用来指明将所有的log信息存放到什么地方，Log4j中支持多种appender，如 console、files、GUI components、NT Event Loggers等，一个Logger可以拥有多个Appender，也就是你既可以将Log信息输出到屏幕，同时存储到一个文件中。<br />   Layout的作用是控制Log信息的输出方式，也就是格式化输出的信息。<br />   Log4j中将要输出的Log信息定义了5种级别，依次为DEBUG、INFO、WARN、ERROR和FATAL，当输出时，只有级别高过配置中规定的 级别的信息才能真正的输出，这样就很方便的来配置不同情况下要输出的内容，而不需要更改代码，这点实在是方便啊。<br /><br />2、Log4j的配置文件<br />  虽然可以不用配置文件，而在程序中实现配置，但这种方法在如今的系统开发中显然是不可取的，能采用配置文件的地方一定一定要用配置文件。Log4j支持两 种格式的配置文件：XML格式和Java的property格式，本人更喜欢后者，首先看一个简单的例子吧，如下：<br /><br /><pre class="overflow"> log4j.rootLogger=debug, stdout, R<br />  log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />  log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br /><br />  # Pattern to output the caller's file name and line number.<br />  log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n<br /><br />  log4j.appender.R=org.apache.log4j.RollingFileAppender<br />  log4j.appender.R.File=example.log<br />  log4j.appender.R.MaxFileSize=100KB<br /><br />  # Keep one backup file<br />  log4j.appender.R.MaxBackupIndex=1<br /><br />  log4j.appender.R.layout=org.apache.log4j.PatternLayout<br />  log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n</pre>         <br /><br />  首先，是设置root，格式为 log4j.rootLogger=[level],appenderName, ...，其中level就是设置需要输出信息的级别，后面是appender的输出的目的地，appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。配置日志信息输出目的地Appender，其语法为<br />  log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />  log4j.appender.appenderName.option1 = value1<br />  ...<br />  log4j.appender.appenderName.option = valueN<br />Log4j提供的appender有以下几种：<br />  org.apache.log4j.ConsoleAppender（控制台）<br />  org.apache.log4j.FileAppender（文件）<br />  org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件）<br />  org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生新文件）<br />  org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br />配置日志信息的格式（布局），其语法为：<br />  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />  log4j.appender.appenderName.layout.option1 = value1<br />  ....<br />  log4j.appender.appenderName.layout.option = valueN<br />Log4j提供的layout有以下几种：<br />  org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br />  org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br />  org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br />  org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） <br /><br />3、Log4j在程序中的使用<br />  要在自己的类中使用Log4j，首先声明一个静态变量Logger logger=Logger.getLog("classname")；在使用之前，用PropertyConfigurator.configure ("配置文件")配置一下，现在就可以使用了，用法如下：logger.debug("debug message")或者logger.info("info message")，看下面一个小例子：<br /><br /><pre class="overflow"> import com.foo.Bar;<br />  import org.apache.log4j.Logger;<br />  import org.apache.log4j.PropertyConfigurator;<br />  public class MyApp {<br />    static Logger logger = Logger.getLogger(MyApp.class.getName());<br />    public static void main(String[] args) {<br />      // BasicConfigurator replaced with PropertyConfigurator.<br />      PropertyConfigurator.configure(args[0]);<br />      logger.info("Entering application.");<br />      Bar bar = new Bar();<br />      bar.doIt();<br />      logger.info("Exiting application.");<br />    }<br />  }</pre><br /><br /><br />[简介]<br /><br />对于一个典型的Web应用，完善的认证和授权机制是必不可少的，在SpringFramework中，Juergen Hoeller提供的范例JPetStore给了一些这方面的介绍，但还远远不够，Acegi是一个专门为SpringFramework提供安全机制的 项目，全称为Acegi Security System for Spring，当前版本为0.5.1，就其目前提供的功能，应该可以满足绝大多数应用的需求。<br /><br />本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中使用Acegi，而不是详细介绍其中的每个接口、每个类。注意，即使对已经存在的Spring应用，通过下面介绍的步骤，也可以马上享受到Acegi提供的认证和授权。<br /><br />[基础工作]<br />在你的Web应用的lib中添加Acegi下载包中的acegi-security.jar<br /><br />[web.xml]<br />实现认证和授权的最常用的方法是通过filter，Acegi亦是如此，通常Acegi需要在web.xml添加以下5个filter:<br /><br /><pre class="overflow">&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.ui.AutoIntegrationFilter&lt;/filter-class&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;</pre><br /><br />最先引起迷惑的是net.sf.acegisecurity.util.FilterToBeanProxy，Acegi自己的文档上解释是： “What  FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the <br />Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.”，如希望深究的话，去看看源代码应该不难理解。<br /><br />再下来就是添加filter-mapping了：<br /><pre class="overflow">&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;</pre><br /><br />这里，需要注意以下两点：<br />1) 这几个filter的顺序是不能更改的，顺序不对将无法正常工作；<br />2) 如果你的应用不需要安全传输，如https，则将"Acegi Channel Processing Filter"相关内容注释掉即可；<br />3) 如果你的应用不需要Spring提供的远程访问机制，如Hessian and Burlap，将"Acegi HTTP BASIC Authorization <br />Filter"相关内容注释掉即可。<br /><br />[applicationContext.xml]<br />接下来就是要添加applicationContext.xml中的内容了，从刚才FilterToBeanFactory的解释可以看出，真正的filter都<br />在Spring的applicationContext中管理：<br /><br />1) 首先，你的数据库中必须具有保存用户名和密码的table，Acegi要求table的schema必须如下：<br /><br /><pre class="overflow">CREATE TABLE users (<br />    username VARCHAR(50) NOT NULL PRIMARY KEY,<br />    password VARCHAR(50) NOT NULL,<br />    enabled BIT NOT NULL<br />);<br />CREATE TABLE authorities (<br />    username VARCHAR(50) NOT NULL,<br />    authority VARCHAR(50) NOT NULL<br />);<br />CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );<br />ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users<br />(username);</pre><br /><br />2) 添加访问你的数据库的datasource和Acegi的jdbcDao，如下：<br /><br /><pre class="overflow">&lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;<br />  &lt;property name="driverClassName"&gt;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="url"&gt;&lt;value&gt;${jdbc.url}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="username"&gt;&lt;value&gt;${jdbc.username}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="password"&gt;&lt;value&gt;${jdbc.password}&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br />  &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />3) 添加DaoAuthenticationProvider:<br /><br /><pre class="overflow">&lt;bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />  &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br />  &lt;property name="userCache"&gt;&lt;ref bean="userCache"/&gt;&lt;/property&gt;<br />&lt;/bean&gt;<br /><br />&lt;bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;<br />  &lt;property name="minutesToIdle"&gt;&lt;value&gt;5&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />如果你需要对密码加密，则在daoAuthenticationProvider中加入：&lt;property name="passwordEncoder"&gt;&lt;ref <br />bean="passwordEncoder"/&gt;&lt;/property&gt;，Acegi提供了几种加密方法，详细情况可看包<br />net.sf.acegisecurity.providers.encoding<br /><br />4) 添加authenticationManager:<br /><br /><pre class="overflow">&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br />  &lt;property name="providers"&gt;<br />    &lt;list&gt;<br />      &lt;ref bean="daoAuthenticationProvider"/&gt;<br />    &lt;/list&gt;<br />   &lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />5) 添加accessDecisionManager:<br /><br /><pre class="overflow">&lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br />  &lt;property name="allowIfAllAbstainDecisions"&gt;<br />    &lt;value&gt;false&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="decisionVoters"&gt;<br />    &lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;</pre><br /><br />6) 添加authenticationProcessingFilterEntryPoint:<br /><br /><pre class="overflow">&lt;bean id="authenticationProcessingFilterEntryPoint" <br />class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;<br />  &lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />其中acegilogin.jsp是登陆页面，一个最简单的登录页面如下：<br /><br /><pre class="overflow">&lt;%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %&gt;<br />&lt;%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %&gt;<br />&lt;%@ page import="net.sf.acegisecurity.AuthenticationException" %&gt;<br />&lt;html&gt;<br />  &lt;head&gt;<br />    &lt;title&gt;Login&lt;/title&gt;<br />  &lt;/head&gt;<br /><br />  &lt;body&gt;<br />    &lt;h1&gt;Login&lt;/h1&gt;<br />    &lt;form action="&lt;c:url value='j_acegi_security_check'/&gt;" method="POST"&gt;<br />      &lt;table&gt;<br />        &lt;tr&gt;&lt;td&gt;User:&lt;/td&gt;&lt;td&gt;&lt;input type='text' name='j_username'&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td&gt;Password:&lt;/td&gt;&lt;td&gt;&lt;input type='password' name='j_password'&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="submit" type="submit"&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="reset" type="reset"&gt;&lt;/td&gt;&lt;/tr&gt;<br />      &lt;/table&gt;<br />    &lt;/form&gt;<br />  &lt;/body&gt;<br />&lt;/html&gt;</pre><br /><br />7) 添加filterInvocationInterceptor:<br /><br /><pre class="overflow">&lt;bean id="filterInvocationInterceptor" <br />class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />  &lt;property name="authenticationManager"&gt;<br />    &lt;ref bean="authenticationManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="accessDecisionManager"&gt;<br />    &lt;ref bean="accessDecisionManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="objectDefinitionSource"&gt;<br />    &lt;value&gt;<br />      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />      \A/sec/administrator.*\Z=ROLE_SUPERVISOR<br />      \A/sec/user.*\Z=ROLE_TELLER<br />    &lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />这里请注意，要objectDefinitionSource中定义哪些页面需要权限访问，需要根据自己的应用需求进行修改，我上面给出<br />的定义的意思是这样的：<br />a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求路径时全部转换为小写<br />b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能访问/sec/administrator*的页面<br />c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用户才能访问/sec/user*的页面<br /><br />8) 添加securityEnforcementFilter:<br /><br /><pre class="overflow">&lt;bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter"&gt;<br />  &lt;property name="filterSecurityInterceptor"&gt;<br />    &lt;ref bean="filterInvocationInterceptor"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="authenticationEntryPoint"&gt;<br />    &lt;ref bean="authenticationProcessingFilterEntryPoint"/&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</pre><br /><br />9) 添加authenticationProcessingFilter:<br /><br /><pre class="overflow">&lt;bean id="authenticationProcessingFilter" <br />class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />  &lt;property name="authenticationManager"&gt;<br />    &lt;ref bean="authenticationManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="authenticationFailureUrl"&gt;<br />    &lt;value&gt;/loginerror.jsp&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="defaultTargetUrl"&gt;<br />    &lt;value&gt;/&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="filterProcessesUrl"&gt;<br />    &lt;value&gt;/j_acegi_security_check&lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</pre><br />其中authenticationFailureUrl是认证失败的页面。<br /><br />10) 如果需要一些页面通过安全通道的话，添加下面的配置:<br /><br /><pre class="overflow">&lt;bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter"&gt;<br />  &lt;property name="channelDecisionManager"&gt;<br />    &lt;ref bean="channelDecisionManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="filterInvocationDefinitionSource"&gt;<br />    &lt;value&gt;<br />      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />      \A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A.*\Z=REQUIRES_INSECURE_CHANNEL<br />    &lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br /><br />&lt;bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl"&gt;<br />  &lt;property name="channelProcessors"&gt;<br />    &lt;list&gt;<br />      &lt;ref bean="secureChannelProcessor"/&gt;<br />      &lt;ref bean="insecureChannelProcessor"/&gt;<br />    &lt;/list&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/&gt;<br />&lt;bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/&gt;</pre><br /><br />[缺少了什么？]<br />Acegi目前提供了两种"secure object"，分别对页面和方法进行安全认证管理，我这里介绍的只是利用<br />FilterSecurityInterceptor对访问页面的权限控制，除此之外，Acegi还提供了另外一个Interceptor――<br />MethodSecurityInterceptor，它结合runAsManager可实现对对象中的方法的权限控制，使用方法可参看Acegi自带的文档<br />和contact范例。<br /><br />[最后要说的]<br />本来以为只是说明如何使用Acegi而已，应该非常简单，但真正写起来才发现想要条理清楚的理顺所有需要的bean还是很<br />困难的，但愿我没有遗漏太多东西，如果我的文章有什么遗漏或错误的话，还请参看Acegi自带的quick-start范例，但请<br />注意，这个范例是不能直接拿来用的。<br />分析和学习Spring中的jpetstore用户管理 <br />  存在用户的系统，必然需要用户的登录和认证，今天就通过分析Spring中自带的jpetstore的例子来学习一下如何实现在Spring构架的系统中用户登录。<br />1、首先从注册用户开始，先看看jpetstore-servlet.xml中关于注册用户的bean定义，从定义命名中就可以看出下面这段就是注册用户的：<br />  <pre class="overflow">&lt;bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController"&gt;<br />    &lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br />    &lt;property name="validator"&gt;&lt;ref bean="accountValidator"/&gt;&lt;/property&gt;<br />    &lt;property name="successView"&gt;&lt;value&gt;index&lt;/value&gt;&lt;/property&gt;<br />  &lt;/bean&gt;</pre><br />1). formView呢？从AccountFormController的构造函数中得到，原来为EditAccountForm；  <br />2). EditoAccountForm.jsp中显得非常乱，其实没有多少难理解的地方，最主要的是这个form既是添加新用户的，又是编辑用户信息的，所以显得有点乱糟糟的。<br />2、添加好了新用户，接下来看看如何登录，在jpetstore-servlet中发现这两个相关bean定义，如下：<br />  <pre class="overflow">&lt;bean name="/shop/signon.do" class="org.springframework.samples.jpetstore.web.spring.SignonController"&gt;<br />    &lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean name="/shop/signonForm.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController"&gt;<br />    &lt;property name="viewName"&gt;&lt;value&gt;SignonForm&lt;/value&gt;&lt;/property&gt;<br />  &lt;/bean&gt;</pre><br />1). 第二个bean是在运行时用户输入用户名和密码的form，叫做SignonForm，对于这个 ParameterizableViewController，用文档里的话说这是最简单的Controller，其作用就是在运行中指向 Controller而不是直接指向jsp文件，仅此而已。<br />2). SignonForm.jsp，里面就是一个简单的form，其action就是第一个bean，即/shop/signon.do，最需要注意的是 signonForwardAction，其主要作用是forward到需要输入用户名和密码的那个页面上去，这个变量哪里来的呢？看看下面：<br />  <pre class="overflow">&lt;bean id="secureHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;<br />    &lt;property name="interceptors"&gt;<br />      &lt;list&gt;<br />        &lt;ref bean="signonInterceptor"/&gt;<br />      &lt;/list&gt;<br />    &lt;/property&gt;<br />    &lt;property name="urlMap"&gt;<br />      &lt;map&gt;<br />        &lt;entry key="/shop/editAccount.do"&gt;&lt;ref local="secure_editAccount"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/listOrders.do"&gt;&lt;ref local="secure_listOrders"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/newOrder.do"&gt;&lt;ref local="secure_newOrder"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/viewOrder.do"&gt;&lt;ref local="secure_viewOrder"/&gt;&lt;/entry&gt;<br />      &lt;/map&gt;<br />    &lt;/property&gt;<br />  &lt;/bean&gt;</pre><br />  原来，上面的signonInterceptor实现了preHandle，因此在请求上面的map页面时，首先要经过这个Interceptor，看看 SignonInterceptor的源码，原来在其中为signon.jsp赋予一个signonForwardAction对象，呵呵，总算明白了。<br />3). 接下来去学习一下SignonController，其主体部分中可以看出，首先取出用户输入的username和password，然后到数据库中验证 有没有这个用户，如果没有这个用户，返回各错误页面；如果成功，首先生成一个UserSession对象，在request的session加入这个 userSession，注意这部分代码中给出了PagedListHolder分页的简单使用方法，关于分页显示，以后再学习吧。<br />3、登录成功后，就可以根据不同的用户设施不同的行为了，取得用户信息，无非就是从session取出userSession即可。<img src ="http://www.blogjava.net/rain1102/aggbug/88847.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-19 16:40 <a href="http://www.blogjava.net/rain1102/articles/88847.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于组的用户权限管理在Spring框架下的实现</title><link>http://www.blogjava.net/rain1102/articles/88791.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 19 Dec 2006 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/88791.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/88791.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/88791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/88791.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/88791.html</trackback:ping><description><![CDATA[<p>在几乎所有的web应用中都需要对访问者(用户)进行权限管理, 因为我们希望某些页面只对特定的用户开放, 以及某些操作只有符合身份的用户才能进行. 这之中涉及到了身份验证和权限管理. 只有单用户系统和多用户单权限系统才不需要权限管理. </p>
		<p>在本文中, 使用了基于组的权限管理, 并在Spring框架下利用HandlerInterceptorAdapter和Hibernate进行实现. </p>
		<p>User的结构是: <br />public class User {<br /><br />	private int id;<br /><br />	private String name;<br /><br />	private String password;<br /><br />	private Set&lt;String&gt; groups = new HashSet&lt;String&gt;();<br />}<br /></p>
		<p>UserGroup表: </p>
		<pre>user:int
group:String
</pre>
		<p>使用联合主键, 在Java中没有对应的类. </p>
		<p>Hibernate映射文件是: <br />&lt;hibernate-mapping auto-import="true" default-lazy="false"&gt;<br />	&lt;class name="net.ideawu.User" table="User"&gt;<br />		&lt;cache usage="read-write" /&gt;<br />		&lt;id name="id" column="id"&gt;<br />			&lt;generator class="native"/&gt;<br />		&lt;/id&gt;<br />		&lt;property name="name" column="name"/&gt;<br />		&lt;property name="password" column="password"/&gt;<br />		&lt;set name="groups" table="UserGroup" cascade="save-update" lazy="false"&gt;<br />			&lt;key column="user" /&gt;<br />			&lt;element column="`group`" type="string" /&gt;<br />		&lt;/set&gt;<br />	&lt;/class&gt;<br />&lt;/hibernate-mapping&gt;<br />一切的身份验证交给一个继承HandlerInterceptorAdapter的类来做: <br />import org.springframework.web.util.UrlPathHelper;<br />import org.springframework.util.AntPathMatcher;<br />import org.springframework.util.PathMatcher;<br />...<br /><br />public class AuthorizeInterceptor extends HandlerInterceptorAdapter {<br /><br />	private UrlPathHelper urlPathHelper = new UrlPathHelper();<br /><br />	private PathMatcher pathMatcher = new AntPathMatcher();<br /><br />	private  Properties groupMappings;<br /><br />	/**<br />	 * Attach URL paths to group.<br />	 */<br />	public void setGroupMappings(Properties groupMappings) {<br />		this.groupMappings = groupMappings;<br />	}<br /><br />	public boolean preHandle(HttpServletRequest request,<br />			HttpServletResponse response,<br />			Object handler) throws Exception {<br />		String url = urlPathHelper.getLookupPathForRequest(request);<br />		String group = lookupGroup(url);	// 找出资源所需要的权限, 即组名<br />		if(group == null){	// 所请求的资源不需要保护.<br />			return true;<br />		}<br />		// 如果已经登录, 一个User实例被保存在session中.<br />		User loginUser = (User)request.getSession().getAttribute("loginUser");<br />		ModelAndView mav = new ModelAndView("system/authorizeError");<br />		if(loginUser == null){<br />			mav.addObject("errorMsg", "你还没有登录!");<br />			throw new ModelAndViewDefiningException(mav);<br />		}else{<br />			if(!loginUser.getGroups().contains(group)){<br />				mav.addObject("errorMsg", "授权失败! 你不在 &lt;b&gt;" + group + "&lt;/b&gt; 组!");<br />				throw new ModelAndViewDefiningException(mav);<br />			}<br />			return true;<br />		}<br />	}<br /><br />	/*<br />	 * 查看 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.lookupHandler()<br />	 * Ant模式的最长子串匹配法.<br />	 */<br />	private String lookupGroup(String url){<br />		String group =  groupMappings.getProperty(url);<br />		if (group == null) {<br />			String bestPathMatch = null;<br />			for (Iterator it = this.groupMappings.keySet().iterator(); it.hasNext();) {<br />				String registeredPath = (String) it.next();<br />				if (this.pathMatcher.match(registeredPath, url) &amp;&amp;<br />							(bestPathMatch == null || bestPathMatch.length() &lt;= registeredPath.length())) {<br />					group = this.groupMappings.getProperty(registeredPath);<br />					bestPathMatch = registeredPath;<br />				}<br />			}<br />		}<br />		return group;<br />	}<br />}<br /></p>
		<p>下面我们需要在Spring的应用上下文配置文件中设置: <br /></p>
		<pre>&lt;bean id="authorizeInterceptor" class="net.ideawu.AuthorizeInterceptor"&gt;
	&lt;property name="groupMappings"&gt;
		&lt;value&gt;
			&lt;!-- Attach URL paths to group --&gt;
			/admin/*=admin
		&lt;/value&gt;
	&lt;/property&gt;
&lt;/bean&gt;

&lt;bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
	&lt;property name="interceptors"&gt;
		&lt;list&gt;
			&lt;ref bean="authorizeInterceptor" /&gt;
		&lt;/list&gt;
	&lt;/property&gt;
	&lt;property name="mappings"&gt;
		&lt;value&gt;
			/index.do=indexController
			/browse.do=browseController
			/admin/removeArticle.do=removeArticleController
		&lt;/value&gt;
	&lt;/property&gt;
&lt;/bean&gt;
</pre>
		<p>注意到"/admin/*=admin", 所以/admin目录下的所有资源只有在admin组的用户才能访问, 这样就不用担心普通访客删除文章了. 使用这种方法, 你不需要在removeArticleController中作身份验证和权限管理, 一切都交给AuthorizeInterceptor. </p><img src ="http://www.blogjava.net/rain1102/aggbug/88791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-19 14:40 <a href="http://www.blogjava.net/rain1102/articles/88791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>webwork+spring+hibernate架构目录结构</title><link>http://www.blogjava.net/rain1102/articles/86877.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Mon, 11 Dec 2006 05:21:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/86877.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/86877.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/86877.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/86877.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/86877.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="500" border="0">
				<tbody>
						<tr>
								<td width="10">
								</td>
								<td width="490">
										<span class="oblog_text">
												<p class="MsoNormal">
														<span lang="EN-US">
																<span>     转自<a href="/black_zerg/archive/2005/05/30/5327.html">http://www.blogjava.net/black_zerg/archive/2005/05/30/5327.html</a>  </span>
														</span>
												</p>
												<table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1">
														<tbody>
																<tr>
																		<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 213.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="284">
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.blogjava.net/images/blogjava_net/black_zerg/1560/o_image002.jpg" width="200" onload="javascript:if(this.width&gt;1000){this.resized=true;this.style.width=1000;}" border="0" />
																						</span>
																				</p>
																		</td>
																		<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 213.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="284">
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span>       </span>
																						</span>
																						<span style="FONT-FAMILY: 宋体">在</span>
																						<span lang="EN-US">src</span>
																						<span style="FONT-FAMILY: 宋体">目录下为</span>
																						<span lang="EN-US">
																								<a title="Java爱好者" href="/rain1102">Java</a>
																						</span>
																						<span style="FONT-FAMILY: 宋体">源码</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">dao<span>    </span></span>
																						</b>
																						<b>
																								<span style="FONT-FAMILY: 宋体">负责数据访问对象的定义和实现</span>
																								<span lang="EN-US">
																										<?xml:namespace prefix = o /?>
																										<o:p>
																										</o:p>
																								</span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>
																						</span>
																						<span style="FONT-FAMILY: 宋体">其中</span>
																						<span lang="EN-US">Dao</span>
																						<span style="FONT-FAMILY: 宋体">结尾为接口，</span>
																						<span lang="EN-US">Impl</span>
																						<span style="FONT-FAMILY: 宋体">结尾为实现。目前一般用</span>
																						<span lang="EN-US">hibernate</span>
																						<span style="FONT-FAMILY: 宋体">做实现。<br /></span>
																						<b>
																								<span lang="EN-US">domain </span>
																						</b>
																						<b>
																								<span style="FONT-FAMILY: 宋体">实体对象<br /><br /></span>
																						</b>
																						<b>
																								<span lang="EN-US">logic<span>   </span></span>
																						</b>
																						<b>
																								<span style="FONT-FAMILY: 宋体">针对实体对象封装的逻辑</span>
																								<span lang="EN-US">
																										<o:p>
																										</o:p>
																								</span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">
																										<span> </span>
																								</span>
																						</b>
																						<span style="FONT-FAMILY: 宋体">这里</span>
																						<span lang="EN-US">service</span>
																						<span style="FONT-FAMILY: 宋体">是外观接口，</span>
																						<span lang="EN-US">serviceimpl</span>
																						<span style="FONT-FAMILY: 宋体">是实现，考虑目前情况简单，并没有进一步分离逻辑，业务逻辑都在</span>
																						<span lang="EN-US">impl</span>
																						<span style="FONT-FAMILY: 宋体">中完成。</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">web<span>    </span></span>
																						</b>
																						<b>
																								<span style="FONT-FAMILY: 宋体">界面相关的</span>
																								<span lang="EN-US">
																										<a title="Java爱好者" href="/rain1102">Java</a>
																								</span>
																						</b>
																						<b>
																								<span style="FONT-FAMILY: 宋体">类</span>
																								<span lang="EN-US">
																										<o:p>
																										</o:p>
																								</span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>
																								<span style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0cm; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid">common</span>
																						</span>
																						<span style="FONT-FAMILY: 宋体">是一些常用类，如处理中文问题的</span>
																						<span lang="EN-US">filter.</span>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>
																								<span style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0cm; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid">displaytag</span>
																						</span>
																						<span style="FONT-FAMILY: 宋体">中放了</span>
																						<span lang="EN-US">displaytag</span>
																						<span style="FONT-FAMILY: 宋体">相关的类，多为</span>
																						<span lang="EN-US">wrapper.</span>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>
																								<span style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0cm; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid">webwork</span>
																						</span>
																						<span style="FONT-FAMILY: 宋体">中都是对应的</span>
																						<span lang="EN-US">action</span>
																						<span style="FONT-FAMILY: 宋体">，</span>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 10.5pt">
																						<span style="FONT-FAMILY: 宋体">其中</span>
																						<span lang="EN-US"> BaseAction</span>
																						<span style="FONT-FAMILY: 宋体">是基本的抽象类，基本后续开发应继承此类</span>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 10.5pt">
																						<span lang="EN-US">CrudAction</span>
																						<span style="FONT-FAMILY: 宋体">是为了一般的</span>
																						<span lang="EN-US">Crud</span>
																						<span style="FONT-FAMILY: 宋体">工作而作的一个抽象类，可以继承用来简化工作。</span>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 10.5pt">
																						<span style="FONT-FAMILY: 宋体">而</span>
																						<span lang="EN-US">CaseDispatcher</span>
																						<span style="FONT-FAMILY: 宋体">负责菜单点击后分发到相关</span>
																						<span lang="EN-US">Action</span>
																						<span style="FONT-FAMILY: 宋体">，同时处理权限和</span>
																						<span lang="EN-US">session</span>
																						<span style="FONT-FAMILY: 宋体">工作。<br />  </span>
																						<span style="FONT-FAMILY: 宋体">其他</span>
																						<span lang="EN-US">action</span>
																						<span style="FONT-FAMILY: 宋体">按模块进行了组织</span>
																				</p>
																		</td>
																</tr>
																<tr>
																		<td style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: 1pt solid; WIDTH: 213.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: 1pt solid" valign="top" width="284">
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.blogjava.net/images/blogjava_net/black_zerg/1560/o_image004.jpg" width="200" onload="javascript:if(this.width&gt;1000){this.resized=true;this.style.width=1000;}" border="0" />
																						</span>
																				</p>
																		</td>
																		<td style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 213.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: 1pt solid" valign="top" width="284">
																				<p class="MsoNormal">
																						<span style="FONT-FAMILY: 宋体">左边是</span>
																						<span lang="EN-US">webroot</span>
																						<span style="FONT-FAMILY: 宋体">的结构</span>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<o:p> </o:p>
																						</span>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<o:p> </o:p>
																						</span>
																				</p>
																				<p class="MsoNormal">
																						<span style="FONT-FAMILY: 宋体">重要的配置文件有：</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">Spring<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 5.25pt">
																						<span lang="EN-US">applicationContext.xml</span>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 5.25pt">
																						<span lang="EN-US">applicationContext-db.xml</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">Webwork<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 5.25pt">
																						<span lang="EN-US">xwork.xml</span>
																				</p>
																				<p class="MsoNormal" style="TEXT-INDENT: 5.25pt">
																						<span lang="EN-US">webwork.properties</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">i18n<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>labels.properties</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">log4j<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>log4j.properties</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">displaytag<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>displaytag.properties</span>
																				</p>
																				<p class="MsoNormal">
																						<b>
																								<span lang="EN-US">dbConnect<o:p></o:p></span>
																						</b>
																				</p>
																				<p class="MsoNormal">
																						<span lang="EN-US">
																								<span> </span>jdbc.properties</span>
																				</p>
																		</td>
																</tr>
														</tbody>
												</table>
												<p class="MsoNormal">
														<span lang="EN-US">
																<o:p> </o:p>
														</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-FAMILY: 宋体">关于一些技术难点和细节：</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>1．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">各框架连接：</span>
														<span lang="EN-US">spring</span>
														<span style="FONT-FAMILY: 宋体">到</span>
														<span lang="EN-US">hibernate</span>
														<span style="FONT-FAMILY: 宋体">使用</span>
														<span lang="EN-US">spring</span>
														<span style="FONT-FAMILY: 宋体">的</span>
														<span lang="EN-US">hibernate</span>
														<span style="FONT-FAMILY: 宋体">支持。</span>
														<span lang="EN-US">Spring</span>
														<span style="FONT-FAMILY: 宋体">到</span>
														<span lang="EN-US">webwork</span>
														<span style="FONT-FAMILY: 宋体">使用</span>
														<span lang="EN-US">autoware</span>
														<span style="FONT-FAMILY: 宋体">的拦截机制自动装配。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>2．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">列表的问题，采用</span>
														<span lang="EN-US">displaytag</span>
														<span style="FONT-FAMILY: 宋体">。功能强大，使用简洁，可实现排序和数据导出。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>3．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">数据下载，使用</span>
														<span lang="EN-US">displaytag</span>
														<span style="FONT-FAMILY: 宋体">自带的</span>
														<span lang="EN-US">excel</span>
														<span style="FONT-FAMILY: 宋体">下载</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>4．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">文件上传，使用</span>
														<span lang="EN-US">webwork</span>
														<span style="FONT-FAMILY: 宋体">提供的解决方案，用拦截机制实现。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>5．</span>
														</span>
														<span lang="EN-US">jsp</span>
														<span style="FONT-FAMILY: 宋体">代码组织方面，我们使用</span>
														<span lang="EN-US">taglib</span>
														<span style="FONT-FAMILY: 宋体">和</span>
														<span lang="EN-US">css</span>
														<span style="FONT-FAMILY: 宋体">技术使</span>
														<span lang="EN-US">jsp</span>
														<span style="FONT-FAMILY: 宋体">中页面逻辑减少到最小，一般情况完全可以不使用</span>
														<span lang="EN-US">&lt;% %&gt;</span>
														<span style="FONT-FAMILY: 宋体">的</span>
														<span lang="EN-US">script</span>
														<span style="FONT-FAMILY: 宋体">段</span>
														<span style="FONT-FAMILY: 宋体">。同时我们使用两个</span>
														<span lang="EN-US">include</span>
														<span style="FONT-FAMILY: 宋体">来包含常用的</span>
														<span lang="EN-US">taglib</span>
														<span style="FONT-FAMILY: 宋体">定义，</span>
														<span lang="EN-US">js</span>
														<span style="FONT-FAMILY: 宋体">引用和</span>
														<span lang="EN-US">html</span>
														<span style="FONT-FAMILY: 宋体">结构，使</span>
														<span lang="EN-US">jsp</span>
														<span style="FONT-FAMILY: 宋体">代码非常简洁。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>6．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">中文问题</span>
														<span style="FONT-FAMILY: 宋体">我们使用</span>
														<span lang="EN-US">filter</span>
														<span style="FONT-FAMILY: 宋体">来解决页面</span>
														<span lang="EN-US">gbk</span>
														<span style="FONT-FAMILY: 宋体">到</span>
														<span lang="EN-US">
																<a title="Java爱好者" href="/rain1102">Java</a>
														</span>
														<span style="FONT-FAMILY: 宋体">程序</span>
														<span lang="EN-US">unicode</span>
														<span style="FONT-FAMILY: 宋体">的转换，同时通过正确的设置数据库连接</span>
														<span lang="EN-US">url</span>
														<span style="FONT-FAMILY: 宋体">完成和数据库之间的交互。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>7．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span lang="EN-US">I18n</span>
														<span style="FONT-FAMILY: 宋体">国际化。我们要求在</span>
														<span lang="EN-US">jsp</span>
														<span style="FONT-FAMILY: 宋体">代码中不出现中文，所有提示信息都通过资源文件</span>
														<span lang="EN-US">labels.properties</span>
														<span style="FONT-FAMILY: 宋体">来完成。页面中可以使用</span>
														<span lang="EN-US">jstl</span>
														<span style="FONT-FAMILY: 宋体">或</span>
														<span lang="EN-US">webwork</span>
														<span style="FONT-FAMILY: 宋体">标签来调用。</span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">
														<span lang="EN-US">
																<span>8．<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">  </span></span>
														</span>
														<span style="FONT-FAMILY: 宋体">界面验证问题。使用</span>
														<span lang="EN-US">webwork</span>
														<span style="FONT-FAMILY: 宋体">的</span>
														<span lang="EN-US">validate</span>
														<span style="FONT-FAMILY: 宋体">机制用</span>
														<span lang="EN-US">xml</span>
														<span style="FONT-FAMILY: 宋体">定义，或在</span>
														<span lang="EN-US">action</span>
														<span style="FONT-FAMILY: 宋体">中代码判断。</span>
												</p>
										</span>
								</td>
						</tr>
				</tbody>
		</table><img src ="http://www.blogjava.net/rain1102/aggbug/86877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-12-11 13:21 <a href="http://www.blogjava.net/rain1102/articles/86877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>与DataSource一起工作</title><link>http://www.blogjava.net/rain1102/articles/81730.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 17 Nov 2006 03:45:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/81730.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/81730.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/81730.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/81730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/81730.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">与</span>
				<span lang="EN-US">DataSource</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一起工作</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为了对数据库执行任何的</span>
				<span lang="EN-US">JDBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">操作，必须有一个</span>
				<span lang="EN-US">Connection</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。在</span>
				<span lang="EN-US">Spring</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">DAO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">框架里，</span>
				<span lang="EN-US">Connection</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象是通过</span>
				<span lang="EN-US">DataSource</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">获得的。</span>
				<span lang="EN-US">Spring</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了几种选择让你的应用获得</span>
				<span lang="EN-US">DataSource</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt">
				<span lang="EN-US">1．</span>
				<font color="#006400">
						<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">从</span>
						<span lang="EN-US">JNDI</span>
						<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">获得</span>
						<span lang="EN-US">DataSource</span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span lang="EN-US">&lt;bean id=”dataSource” class=”org.springframework.jndi.JndiObjectFactoryBean”&gt;</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 12pt">
				<span lang="EN-US">&lt;property name=”jndiName”&gt;</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span lang="EN-US">
						<span style="mso-spacerun: yes">      </span>&lt;value&gt;java:comp/env/jdbc/myDatasource&lt;/value&gt;</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 12pt">
				<span lang="EN-US">&lt;/property&gt;</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span lang="EN-US">&lt;/bean&gt;</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt">
				<span lang="EN-US">2．</span>
				<font color="#006400">
						<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建一个</span>
						<span lang="EN-US">DataSource</span>
						<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">连接池</span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span lang="EN-US">&lt;<span class="tag-name">bean</span> <span class="attribute">id</span>=<span class="attribute-value">" dataSource"</span> <span class="attribute">class</span>=<span class="attribute-value">"org.apache.commons.dbcp.BasicDataSource"&gt;<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">  </span>&lt;property name=”driver”&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">     </span>&lt;value&gt;${db.driver}&lt;/value&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">  </span>&lt;/property&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">&lt;property name=”url”&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">    </span>
								<span style="mso-spacerun: yes"> </span>&lt;value&gt;${db.url}&lt;/value&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">  </span>&lt;/property&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">&lt;property name=”username”&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">     </span>&lt;value&gt;${db.username}&lt;/value&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">  </span>&lt;/property&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">&lt;property name=”password”&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">     </span>&lt;value&gt;${db.password}&lt;/value&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">
								<span style="mso-spacerun: yes">  </span>&lt;/property&gt;<o:p></o:p></span>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
				<span class="attribute-value">
						<span lang="EN-US">&lt;/bean&gt;</span>
				</span>
		</p><img src ="http://www.blogjava.net/rain1102/aggbug/81730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-11-17 11:45 <a href="http://www.blogjava.net/rain1102/articles/81730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring中基础核心接口介绍</title><link>http://www.blogjava.net/rain1102/articles/81697.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 17 Nov 2006 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/81697.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/81697.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/81697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/81697.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/81697.html</trackback:ping><description><![CDATA[<p>spring中基础核心接口总结<br />理解这几个接口，及其实现类就可以快速了解spring,具体的用法参考其他spring资料</p>
		<p>1.<font color="#006400">BeanFactory</font>最基础最核心的接口<br />重要的实现类有：<br />XmlBeanFactory,以及ApplicationContext接口下的类</p>
		<p>2.<font color="#006400">Resource</font>接口,可以通用地访问文件资源<br />1)<font color="#ff1493">ClassPathResource</font>:读取得形式为"classpath:ApplicationContext.xml"<br />2)<font color="#ff1493">FileStstemResource</font>:读取得形式为"file:c:\spring\src\ApplicationContext.xml"<br />3)<font color="#ff1493">ServletContextResource</font>:读取得形式为"WEB-INF\ApplicationContext.xml"<br />//ResourceLoader类用于载入Resource</p>
		<p>3.<font color="#006400">FactoryBean</font>工厂bean<br />它本身在bean factory中定义，同时又是用于创建目标bean的工厂<br />spring有以下实现:<br />1)<font color="#ff1493">JndiObjectFactoryBean</font>:通过JNDI查找获取对象<br />2)<font color="#ff1493">LocalSessionFactoryBean</font>:用于在本地装配Hibernate SessionFactory<br />3)<font color="#ff1493">LocalSessionFactoryBean</font>:用于在本地装配JDO PersistenceManagerFactory<br />4)<font color="#ff1493">ProxyFactoryBean</font>:用于获取AOP的代理<br />5)<font color="#ff1493">TransactionProxyFactoryBean</font>:用于为对象创建事务代理，用于实现简捷易用的声明性事务代理<br />6)<font color="#ff1493">RmiProxyFactoryBean</font>:为通过RMI访问的远程对象创建一个代理</p>
		<p>4.<font color="#006400">ApplicationContext</font>加强了BeanFactory的功能，支持以下功能<br />1)国际化支持<br />2)资源访问<br />3)事件监听机制<br />它的重要的实现类有：<br />FileSystemXmlApplicationContext,ClassPathXmlApplication,XmlWebApplicationContext</p>
		<p>5.<font color="#006400">Bean生命周期的回调接口<br /></font>BeanFactoryPostProcessor,InitializingBean,DisposableBean,BeanFactoryAware,ApplicationContextAware,ResourceLoader,BeanPostProcessor</p>
		<p>6.<font color="#006400">MessageSource</font>接口<br />它的实现类有ResourceBundleMessageSource,ReloadableResourceBundleMessageSource.后者在属性文件修改后会重新载入</p><img src ="http://www.blogjava.net/rain1102/aggbug/81697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-11-17 10:27 <a href="http://www.blogjava.net/rain1102/articles/81697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring中事务的属性</title><link>http://www.blogjava.net/rain1102/articles/81695.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 17 Nov 2006 02:22:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/81695.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/81695.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/81695.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/81695.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/81695.html</trackback:ping><description><![CDATA[1.传播行为<br />定义了关于客户端和被调用方法的事务边界。传播规则就是在说明新的事务是否要被启动或是挂起，或者方法是否要在事务环境中运行。<br />spring定义了7种不同的传播行为。<br />1)<font color="#008000">PROPAGATION_MANDATORY<br /></font>   表明方法必须要在事务中运行。如果事务不存在，抛出异常<br />2)<font color="#008000">PROPAGATION_NESTED<br /></font>   表示如果当前已经存在一个事务，则该方法应当运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独地提交或回滚。如果当前事务不存在，就相当于PROPAGATION_REQUIRED<br />3)<font color="#008000">PROPAGATION_NEVER</font><br />  表示当前的方法不应该运行在一个事务上下文中。如果当前存在一个事务，则会抛出一个异常。<br />4)<font color="#008000">PROPAGATION_NOT_SUPPORTED<br /></font>表示该方法不应该在事务中运行。如果一个现有的事务正在运行中。它将在该方法的运行期间被挂起<br />5)<font color="#008000">PROPAGATION_REQUIRED<br /></font>表示当前方法必须运行在一个事务中。如果一个现有的事务正在运行中，该方法将运行在这个事务中。否则的话，就要开始一个新的事务。<br />6)<font color="#008000">PROPAGATION_REQUIRES_NEW<br /></font>表示当前方法必须运行在它自己的事务中。如果一个现有事务在运行的话，将在这个方法运行期间被挂起。<br />7)<font color="#008000">PROPAGATION_SUPPORTS</font><br />表示当前方法不需要事务处理环境，但如果有一个事务已经在运行的话，这个方法也可以在这个事务中运行<br />2.隔离级别<br />多个事务并发运行的关系。因为并发会导致以下问题<br />.脏读(Dirty read) 一个事务读取了被另一个事务改写但还没提交的数据。<br />.不可重复读(Nonrepeatable read) 一个事务执行相同的查询两次或两次以上，但每次查询结果都不同时。这由于另一个并发事务在两次查询之间更新了数据<br />.幻读(Phantom read)<br />当一个事务读取几行记录后，另一个并发事务插入一些记录，就发生了幻读<br />spring定义了以下5种隔离关系<br />1)<font color="#008000">ISOLATION_DEFAULT</font><br />使用后端数据库默认得隔离级别<br />2)<font color="#008000">ISOLATION_READ_UNCOMMITTED<br /></font>允许你读取还未提交的改变了的数据。可能导致脏读，不可重复读，幻读<br />3)<font color="#008000">ISOLATION_READ_COMMITTTED<br /></font>运行在并发事务已经提价后读取。可防止脏读，但不可重复读，幻读都有可能发生<br />4)<font color="#008000">ISOLATION_REPEATABLE_READ<br /></font>对相同字段的多次读取结果是一致的，除非数据被事务本身。可防止脏读，不可重复读，但幻读仍可能发生。<br />5)<font color="#008000">ISOLATION_SERIALIZABLE<br /></font>完全服从ACID的隔离级别，确保不发生脏读，不可重复读，幻读。它的典型做法就是完全锁定在事务中涉及的数据表。因此它是最慢地。<br />3.只读提示<br />通过只读属性，数据库可以对事务进行优化。<br />4.事务超时时间<br />设置了的话，事务在超过这个时间后就自动回滚。避免占用资源过久。<img src ="http://www.blogjava.net/rain1102/aggbug/81695.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-11-17 10:22 <a href="http://www.blogjava.net/rain1102/articles/81695.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ProxyFactoryBean的属性</title><link>http://www.blogjava.net/rain1102/articles/81692.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 17 Nov 2006 02:18:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/81692.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/81692.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/81692.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/81692.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/81692.html</trackback:ping><description><![CDATA[<font color="#cc0033">target</font>:代理的目标类<br /><font color="#cc0033">proxyInterfaces</font>:代理类应该实现的接口列表<br /><font color="#cc0033">interceptorNames</font>:需要应用到目标对象上的通知Bean的名字.可以是拦截器,advisor和其他通知类型的名字。这个属性必须按照在BeanFactory中的顺序设置<br /><font color="#cc0066">singleton</font>:在每次调用getBean时，工厂是否返回的是同一个代理实例。如果使用的是有状态通知，应该设置为false<br /><font color="#cc0066">aopProxyFactory</font>:使用的ProxyFactoryBean实现。Spring带有两种实现(JDK动态代理和CGLIB)。通常不需要使用这个属性<br /><font color="#cc0066">exposeProxy</font>:目标对象是否需要得到当前的代理。通过调用AopContext.getCurrentProxy实现。<br /><font color="#cc0066">frozen</font>:一旦工厂被创建，是否可以修改代理的通知。当设置为true时，在运行时就不能修改ProxyFactoryBean了。通常不需要使用这个属性。<br /><font color="#cc0066">optimize</font>：是否对创建的代理进行优化(只适用于CGLIB)<br /><font color="#cc0066">ProxyTargetClass</font>：是否代理目标类，而不是实现接口。只能在使用CGLIB时使用<br /><img src ="http://www.blogjava.net/rain1102/aggbug/81692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-11-17 10:18 <a href="http://www.blogjava.net/rain1102/articles/81692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中的AOP实现</title><link>http://www.blogjava.net/rain1102/articles/71636.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Mon, 25 Sep 2006 00:47:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/71636.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/71636.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/71636.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/71636.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/71636.html</trackback:ping><description><![CDATA[
		<p>
				<strong>接口</strong>
				<br />package com.rain.bean;</p>
		<p>public interface Bean {<br /> public void theMethod();<br />}</p>
		<p>
				<strong>JavaBean</strong>
				<br />package com.rain.bean;</p>
		<p>public class BeanImpl implements Bean {</p>
		<p> public void theMethod() {<br />  // TODO Auto-generated method stub<br />  System.out.println(this.getClass().getName()+"."+new Exception().getStackTrace()[0].getMethodName()+"()"+"Says Hello!");<br /> }<br />}<br /><br /><strong>MethodBeforeAdvice</strong><br />package com.rain.bean;</p>
		<p>import java.lang.reflect.Method;<br />import org.springframework.aop.MethodBeforeAdvice;</p>
		<p>public class TestBeforeAdvice implements MethodBeforeAdvice {</p>
		<p> public void before(Method arg0, Object[] arg1, Object arg2)<br />   throws Throwable {<br />  // TODO Auto-generated method stub<br />  System.out.println("Hello world! (by "+this.getClass().getName()+")");<br /> }<br />}<br /><br /><strong>applicationContext.xml</strong><br />&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;</p>
		<p>&lt;beans&gt;<br />&lt;!--CONFIG--&gt;<br />   &lt;bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;<br />     &lt;property name="proxyInterfaces"&gt;<br />       &lt;value&gt;com.rain.bean.Bean&lt;/value&gt;<br />     &lt;/property&gt;<br />     &lt;property name="target"&gt;<br />       &lt;ref local="beanTarget"/&gt;<br />     &lt;/property&gt;<br />     &lt;property name="interceptorNames"&gt;<br />       &lt;list&gt;<br />         &lt;value&gt;theAdvisor&lt;/value&gt;<br />       &lt;/list&gt;<br />     &lt;/property&gt;<br />   &lt;/bean&gt;<br />&lt;!--CLASS--&gt;<br />   &lt;bean id="beanTarget" class="com.rain.bean.BeanImpl"&gt;&lt;/bean&gt;<br />&lt;!--ADVISOR--&gt;<br />   &lt;bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;<br />     &lt;property name="advice"&gt;<br />       &lt;ref local="theBeforeAdvice"/&gt;<br />     &lt;/property&gt;<br />     &lt;property name="pattern"&gt;<br />       &lt;value&gt;com\.rain\.bean\.Bean\.theMethod&lt;/value&gt;<br />     &lt;/property&gt;<br />   &lt;/bean&gt;<br />&lt;!--ADVICE--&gt;<br />   &lt;bean id="theBeforeAdvice" class="com.rain.bean.TestBeforeAdvice"&gt;&lt;/bean&gt;<br />&lt;/beans&gt;<br /><br /><strong>Test<br /></strong>package com.rain.test;</p>
		<p>import org.springframework.context.ApplicationContext;<br />import org.springframework.context.support.ClassPathXmlApplicationContext;<br />import com.rain.bean.Bean;</p>
		<p>public class TestAOP {</p>
		<p> /**<br />  * @param args<br />  */<br /> public static void main(String[] args) {<br />  // TODO Auto-generated method stub<br />  ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");<br />  Bean x=(Bean)ctx.getBean("bean");<br />  x.theMethod();<br /> }<br />}<br /><br />结果：<br />Hello world! (by com.rain.bean.TestBeforeAdvice)<br />com.rain.bean.BeanImpl.theMethod()Says Hello!<br /><br /><br /></p>
<img src ="http://www.blogjava.net/rain1102/aggbug/71636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-25 08:47 <a href="http://www.blogjava.net/rain1102/articles/71636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring 框架简介</title><link>http://www.blogjava.net/rain1102/articles/70564.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 19 Sep 2006 08:58:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/70564.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/70564.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/70564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/70564.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/70564.html</trackback:ping><description><![CDATA[在这由三部分组成的介绍 Spring 框架的系列文章的第一期中，将开始学习如何用 Spring 技术构建轻量级的、强壮的 J2EE 应用程序。developerWorks 的定期投稿人 Naveen Balani 通过介绍 Spring 框架开始了他由三部分组成的 <i>Spring 系列</i>，其中还将介绍 Spring 面向方面的编程（AOP）和控制反转（IOC）容器。<br /><p>Spring 是一个开源框架，是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构，分层架构允许您选择使用哪一个组件，同时为 J2EE 应用程序开发提供集成的框架。</p><p>在这篇由三部分组成的 <i>Spring 系列</i> 的第 1 部分中，我将介绍 Spring 框架。我先从框架底层模型的角度描述该框架的功能，然后将讨论两个最有趣的模块：Spring 面向方面编程（AOP）和控制反转 （IOC） 容器。接着将使用几个示例演示 IOC 容器在典型应用程序用例场景中的应用情况。这些示例还将成为本系列后面部分进行的展开式讨论的基础，在本文的后面部分，将介绍 Spring 框架通过 Spring AOP 实现 AOP 构造的方式。<br /></p><p><a name="1"><span class="atitle"><strong><font size="4">Spring 框架</font></strong></span></a></p><p>Spring 框架是一个分层架构，由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上，核心容器定义了创建、配置和管理 bean 的方式，如图 1 所示。</p><p><br /><a name="fig1"><b>图 1. Spring 框架的 7 个模块</b></a><br /><img height="288" alt="Spring 框架图示" src="http://www-128.ibm.com/developerworks/cn/java/wa-spring1/spring_framework.gif" width="555" /><br /></p><p>组成 Spring 框架的每个模块（或组件）都可以单独存在，或者与其他一个或多个模块联合实现。每个模块的功能如下： 
</p><ul><li><b>核心容器</b>：核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 <code><font face="Courier" size="1">BeanFactory</font></code>，它是工厂模式的实现。<code><font face="Courier" size="1">BeanFactory</font></code> 使用<i>控制反转</i> （IOC） 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 
</li><li><b>Spring 上下文</b>：Spring 上下文是一个配置文件，向 Spring 框架提供上下文信息。Spring 上下文包括企业服务，例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 
</li><li><b>Spring AOP</b>：通过配置管理特性，Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以，可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP，不用依赖 EJB 组件，就可以将声明性事务管理集成到应用程序中。 
</li><li><b>Spring DAO</b>：JDBC DAO 抽象层提供了有意义的异常层次结构，可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理，并且极大地降低了需要编写的异常代码数量（例如打开和关闭连接）。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。 
</li><li><b>Spring ORM</b>：Spring 框架插入了若干个 ORM 框架，从而提供了 ORM 的对象关系工具，其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。 
</li><li><b>Spring Web 模块</b>：Web 上下文模块建立在应用程序上下文模块之上，为基于 Web 的应用程序提供了上下文。所以，Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 
</li><li><b>Spring MVC 框架</b>：MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口，MVC 框架变成为高度可配置的，MVC 容纳了大量视图技术，其中包括 JSP、Velocity、Tiles、iText 和 POI。 </li></ul><p></p><p>Spring 框架的功能可以用在任何 J2EE 服务器中，大多数功能也适用于不受管理的环境。Spring 的核心要点是：支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象。毫无疑问，这样的对象可以在不同 J2EE 环境 （Web 或 EJB）、独立应用程序、测试环境之间重用。<br /></p><p><a name="2"><span class="atitle"><strong><font size="4">IOC 和 AOP</font></strong></span></a></p><p>控制反转模式（也称作依赖性介入）的基本概念是：不创建对象，但是描述创建它们的方式。在代码中不直接与对象和服务连接，但在配置文件中描述哪一个组件需要哪一项服务。容器 （在 Spring 框架中是 IOC 容器） 负责将这些联系在一起。</p><p>在典型的 IOC 场景中，容器创建了所有对象，并设置必要的属性将它们连接在一起，决定什么时间调用方法。下表列出了 IOC 的一个实现模式。</p><p></p><table cellspacing="4" cellpadding="2" width="80%" border="1"><tbody><tr valign="top"><td>类型 1</td><td>服务需要实现专门的接口，通过接口，由对象提供这些服务，可以从对象查询依赖性（例如，需要的附加服务）</td></tr><tr valign="top"><td>类型 2</td><td>通过 JavaBean 的属性（例如 setter 方法）分配依赖性</td></tr><tr valign="top"><td>类型 3</td><td>依赖性以构造函数的形式提供，不以 JavaBean 属性的形式公开</td></tr></tbody></table><p>Spring 框架的 IOC 容器采用类型 2 和类型3 实现。</p><p><a name="N100FD"><span class="smalltitle"><strong>面向方面的编程</strong></span></a></p><p><i>面向方面的编程</i>，即 AOP，是一种编程技术，它允许程序员对横切关注点或横切典型的职责分界线的行为（例如日志和事务管理）进行模块化。AOP 的核心构造是<i>方面</i>，它将那些影响多个类的行为封装到可重用的模块中。</p><p>AOP 和 IOC 是补充性的技术，它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典型的面向对象开发方式中，可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中，可以反过来将日志服务<i>模块化</i>，并以声明的方式将它们应用到需要日志的组件上。当然，优势就是 Java 类不需要知道日志服务的存在，也不需要考虑相关的代码。所以，用 Spring AOP 编写的应用程序代码是松散耦合的。</p><p>AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。<br /></p><p><a name="3"><span class="atitle"><strong><font size="4">IOC 容器</font></strong></span></a></p><p>Spring 设计的核心是 <code><font face="Courier" size="1">org.springframework.beans</font></code> 包，它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用，而是由服务器将其用作其他多数功能的底层中介。下一个最高级抽象是 <code><font face="Courier" size="1">BeanFactory</font></code> 接口，它是工厂设计模式的实现，允许通过名称创建和检索对象。<code><font face="Courier" size="1">BeanFactory</font></code> 也可以管理对象之间的关系。</p><p><code><font face="Courier" size="1">BeanFactory</font></code> 支持两个对象模型。</p><ul><li><b>单态</b> 模型提供了具有特定名称的对象的共享实例，可以在查询时对其进行检索。Singleton 是默认的也是最常用的对象模型。对于无状态服务对象很理想。 
</li><li><b>原型</b> 模型确保每次检索都会创建单独的对象。在每个用户都需要自己的对象时，原型模型最适合。 </li></ul><p>bean 工厂的概念是 Spring 作为 IOC 容器的基础。IOC 将处理事情的责任从应用程序代码转移到框架。正如我将在下一个示例中演示的那样，Spring 框架使用 JavaBean 属性和配置数据来指出必须设置的依赖关系。</p><p><a name="N10145"><span class="smalltitle"><strong>BeanFactory 接口</strong></span></a></p><p>因为 <code><font face="Courier" size="1">org.springframework.beans.factory.BeanFactory</font></code> 是一个简单接口，所以可以针对各种底层存储方法实现。最常用的 <code><font face="Courier" size="1">BeanFactory</font></code> 定义是 <code><font face="Courier" size="1">XmlBeanFactory</font></code>，它根据 XML 文件中的定义装入 bean，如清单 1 所示。</p><p><br /><a name="N1015B"><b>清单 1. XmlBeanFactory</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">BeanFactory factory = new XMLBeanFactory(new FileInputSteam("mybean.xml"));
</font></code></pre></td></tr></tbody></table><br /><p>在 XML 文件中定义的 Bean 是被消极加载的，这意味在需要 bean 之前，bean 本身不会被初始化。要从 <code><font face="Courier" size="1">BeanFactory</font></code> 检索 bean，只需调用 <code><font face="Courier" size="1">getBean()</font></code> 方法，传入将要检索的 bean 的名称即可，如清单 2 所示。</p><p><br /><a name="N10171"><b>清单 2. getBean()</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">MyBean mybean = (MyBean) factory.getBean("mybean");
</font></code></pre></td></tr></tbody></table><br /><p>每个 bean 的定义都可以是 POJO （用类名和 JavaBean 初始化属性定义） 或 <code><font face="Courier" size="1">FactoryBean</font></code>。<code><font face="Courier" size="1">FactoryBean</font></code> 接口为使用 Spring 框架构建的应用程序添加了一个间接的级别。<br /></p><p><a name="4"><span class="atitle"><strong><font size="4">IOC 示例</font></strong></span></a></p><p>理解控制反转最简单的方式就是看它的实际应用。在对由三部分组成的 <i>Spring 系列</i> 的第 1 部分进行总结时，我使用了一个示例，演示了如何通过 Spring IOC 容器注入应用程序的依赖关系（而不是将它们构建进来）。</p><p>我用开启在线信用帐户的用例作为起点。对于该实现，开启信用帐户要求用户与以下服务进行交互： 
</p><ul><li>信用级别评定服务，查询用户的信用历史信息。 
</li><li>远程信息链接服务，插入客户信息，将客户信息与信用卡和银行信息连接起来，以进行自动借记（如果需要的话）。 
</li><li>电子邮件服务，向用户发送有关信用卡状态的电子邮件。 </li></ul><p><a name="5"><span class="atitle"><strong><font size="4">三个接口</font></strong></span></a></p><p>对于这个示例，我假设服务已经存在，理想的情况是用松散耦合的方式把它们集成在一起。以下清单显示了三个服务的应用程序接口。</p><p><br /><a name="N101AD"><b>清单 3. CreditRatingInterface</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public interface CreditRatingInterface {

   public boolean getUserCreditHistoryInformation(ICustomer iCustomer);

}
</font></code></pre></td></tr></tbody></table><br /><p>清单 3 所示的信用级别评定接口提供了信用历史信息。它需要一个包含客户信息的 <code><font face="Courier" size="1">Customer</font></code> 对象。该接口的实现是由 <code><font face="Courier" size="1">CreditRating</font></code> 类提供的。</p><p><br /><a name="N101C3"><b>清单 4. CreditLinkingInterface</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public interface CreditLinkingInterface {

public String getUrl();

		public void setUrl(String url);

		public void linkCreditBankAccount() throws Exception ;

}
</font></code></pre></td></tr></tbody></table><br /><p>信用链接接口将信用历史信息与银行信息（如果需要的话）连接在一起，并插入用户的信用卡信息。信用链接接口是一个远程服务，它的查询是通过 <code><font face="Courier" size="1">getUrl()</font></code> 方法进行的。URL 由 Spring 框架的 bean 配置机制设置，我稍后会讨论它。该接口的实现是由 <code><font face="Courier" size="1">CreditLinking</font></code> 类提供的。</p><p><br /><a name="N101D9"><b>清单 5. EmailInterface</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public interface EmailInterface {

      public void sendEmail(ICustomer iCustomer);

      public String getFromEmail();

      public void setFromEmail(String fromEmail) ;

      public String getPassword();

      public void setPassword(String password) ;

      public String getSmtpHost() ;

      public void setSmtpHost(String smtpHost);

      public String getUserId() ;

      public void setUserId(String userId);
   }
</font></code></pre></td></tr></tbody></table><br /><p><code><font face="Courier" size="1">EmailInterface</font></code> 负责向客户发送关于客户信用卡状态的电子邮件。邮件配置参数（例如 SMPT 主机、用户名、口令）由前面提到的 bean 配置机制设置。<code><font face="Courier" size="1">Email</font></code> 类提供了该接口的实现。<br /></p><p><a name="6"><span class="atitle"><strong><font size="4">Spring 使其保持松散</font></strong></span></a></p><p>这些接口就位之后，接下来要考虑的就是如何用松散耦合方式将它们集成在一起。在 <a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring1/listing1.html"><font color="#5c81a7">清单 6</font></a> 中可以看到信用卡帐户用例的实现。</p><p>注意，所有的 setter 方法都是由 Spring 的配置 bean 实现的。所有的依赖关系 （也就是三个接口）都可以由 Spring 框架用这些 bean 注入。<code><font face="Courier" size="1">createCreditCardAccount()</font></code> 方法会用服务去执行其余实现。在 <a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring1/listing2.html"><font color="#5c81a7">清单 7 </font></a>中可以看到 Spring 的配置文件。我用箭头突出了这些定义。<br /></p><p><a name="7"><span class="atitle"><strong><font size="4">运行应用程序</font></strong></span></a></p><p>要运行示例应用程序，首先必须 <a href="http://prdownloads.sourceforge.net/springframework/spring-%20framework-1.2-rc2-with-dependencies.zip?download" target="_new"><font color="#5c81a7">下载 Spring 框架</font></a> 及其所有依赖文件。接下来，将框架释放到（比如说）磁盘 <i>c:\</i>，这会创建 <i>C:\spring-framework-1.2-rc2</i> （适用于当前发行版本） 这样的文件夹。在继续后面的操作之前，还必须下载和释放 <a href="http://ant.apache.org/" target="_new"><font color="#5c81a7">Apache Ant</font></a>。</p><p>接下来，将源代码释放到文件夹，例如 <i>c:\</i> 盘，然后创建 <i>SpringProject</i>。将 Spring 库（即 <i>C:\spring-framework-1.2-rc2\dist</i> 下的 <i>spring.jar</i> 和 <i>C:\spring-framework-1.2-rc2\lib\jakarta-commons</i> 下的 <i>commons-logging.jar</i>）复制到 <i>SpringProject\lib</i> 文件夹中。完成这些工作之后，就有了必需的构建依赖关系集。</p><p>打开命令提示符，将当前目录切换到 <i>SpringProject</i>，在命令提示符中输入以下命令：<code><font face="Courier" size="1">build</font></code>。 </p><p>这会构建并运行 <code><font face="Courier" size="1">CreateCreditAccountClient</font></code> 类，类的运行将创建 <code><font face="Courier" size="1">Customer</font></code> 类对象并填充它，还会调用 <code><font face="Courier" size="1">CreateCreditCardAccount</font></code> 类创建并链接信用卡帐户。<code><font face="Courier" size="1">CreateCreditAccountClient</font></code> 还会通过 <code><font face="Courier" size="1">ClassPathXmlApplicationContext</font></code> 装入 Spring 配置文件。装入 bean 之后，就可以通过 <code><font face="Courier" size="1">getBean()</font></code> 方法访问它们了，如清单 8 所示。</p><p><br /><a name="code8"><b>清单 8. 装入 Spring 配置文件</b></a><br /></p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">ClassPathXmlApplicationContext appContext = 
                    new ClassPathXmlApplicationContext(new String[] {
     "springexample-creditaccount.xml"
    });

CreateCreditCardAccountInterface creditCardAccount = 
                    (CreateCreditCardAccountInterface)
	appContext.getBean("createCreditCard");
</font></code></pre></td></tr></tbody></table><p><a name="8"><span class="atitle"><strong><font size="4">结束语</font></strong></span></a></p><p>在这篇由三部分组成的 <i>Spring 系列</i> 的第一篇文章中，我介绍了 Spring 框架的基础。我从讨论组成 Spring 分层架构的 7 个模块开始，然后深入介绍了其中两个模块：Spring AOP 和 IOC 容器。</p><p>由于学习的最佳方法是实践，所以我用一个工作示例介绍了 IOC 模式 （像 Spring 的 IOC 容器实现的那样）如何用松散耦合的方式将分散的系统集成在一起。在这个示例中可以看到，将依赖关系或服务注入工作中的信用卡帐户应用程序，要比从头开始构建它们容易得多。</p><p>请继续关注这一系列的下一篇文章，我将在这里学习的知识基础上，介绍 Spring AOP 模块如何在企业应用程序中提供持久支持，并让您开始了解 Spring MVC 模块和相关插件。</p><img src ="http://www.blogjava.net/rain1102/aggbug/70564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-19 16:58 <a href="http://www.blogjava.net/rain1102/articles/70564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 Spring 更好地处理 Struts 动作</title><link>http://www.blogjava.net/rain1102/articles/70561.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 19 Sep 2006 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/70561.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/70561.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/70561.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/70561.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/70561.html</trackback:ping><description><![CDATA[
		<em>Struts Recipes</em> 的合著者 George Franciscus 将介绍另一个重大的 Struts 整合窍门 —— 这次是将 Struts 应用程序导入 Spring 框架。请跟随 George，他将向您展示如何改变 Struts 动作，使得管理 Struts 动作就像管理 Spring beans 那样。结果是一个增强的 web 框架，这个框架可以方便地利用 Spring AOP 的优势。<br /><p>您肯定已经听说过控制反转 (IOC) 设计模式，因为很长一段时间以来一直在流传关于它的信息。如果您在任何功能中使用过 Spring 框架，那么您就知道其原理的作用。在本文中，我利用这一原理把一个 Struts 应用程序注入 Spring 框架，您将亲身体会到 IOC 模式的强大。</p><p>将一个 Struts 应用程序整合进 Spring 框架具有多方面的优点。首先，Spring 是为解决一些关于 JEE 的真实世界问题而设计的，比如复杂性、低性能和可测试性，等等。第二，Spring 框架包含一个 AOP 实现，允许您将面向方面技术应用于面向对象的代码。第三，一些人可能会说 Spring 框架只有<i>处理</i> Struts 比 Struts 处理自己好。但是这是观点问题，我演示三种将 Struts 应用程序整合到 Spring 框架的方法后，具体由您自己决定使用哪一种。</p><p>我所演示的方法都是执行起来相对简单的，但是它们却具有明显不同的优点。我为每一种方法创建了一个独立而可用的例子，这样您就可以完全理解每种方法。</p><p><a name="N1008F"><span class="atitle"><font face="Arial" size="4"><strong>为什么 Spring 这么了不起？</strong></font></span></a></p><p>Spring 的创立者 Rod Johnson 以一种批判的眼光看待 Java™ 企业软件开发，并且提议很多企业难题都能够通过战略地使用 IOC 模式（也称作依赖注入）来解决。当 Rod 和一个具有奉献精神的开放源码开发者团队将这个理论应用于实践时，结果就产生了 Spring 框架。简言之，Spring 是一个轻型的容器，利用它可以使用一个外部 XML 配置文件方便地将对象连接在一起。每个对象都可以通过显示一个 JavaBean 属性收到一个到依赖对象的引用，留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。</p><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="N1009C"><b>IOC 和 Spring</b></a><br /><p>IOC 是一种使应用程序逻辑外在化的设计模式，所以它是被注入而不是被写入客户机代码中。将 IOC 与接口编程应用结合，就像 Spring 框架那样，产生了一种架构，这种架构能够减少客户机对特定实现逻辑的依赖。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#resources"><font color="#996699">参考资料</font></a> 了解更多关于 IOC 和 Spring 的信息。</p></td></tr></tbody></table></td></tr></tbody></table><p>依赖注入是一个强大的特性，但是 Spring 框架能够提供更多特性。Spring 支持可插拔的事务管理器，可以给您的事务处理提供更广泛的选择范围。它集成了领先的持久性框架，并且提供一个一致的异常层次结构。Spring 还提供了一种使用面向方面代码代替正常的面向对象代码的简单机制。</p><p>Spring AOP 允许您使用<i>拦截器</i> 在一个或多个执行点上拦截应用程序逻辑。加强应用程序在拦截器中的日志记录逻辑会产生一个更可读的、实用的代码基础，所以拦截器广泛用于日志记录。您很快就会看到，为了处理横切关注点，Spring AOP 发布了它自己的拦截器，您也可以编写您自己的拦截器。<br /><br /></p><p><a name="N100B3"><span class="atitle"><font face="Arial" size="4"><strong>整合 Struts 和 Spring</strong></font></span></a></p><p>与 Struts 相似，Spring 可以作为一个 MVC 实现。这两种框架都具有自己的优点和缺点，尽管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多开发团队已经学会在时间紧迫的时候利用 Struts 作为构造高品质软件的基础。Struts 具有如此大的推动力，以至于开发团队宁愿整合 Spring 框架的特性，而不愿意转换成 Spring MVC。没必要进行转换对您来说是一个好消息。Spring 架构允许您将 Struts 作为 Web 框架连接到基于 Spring 的业务和持久层。最后的结果就是现在一切条件都具备了。</p><p>在接下来的小窍门中，您将会了解到三种将 Struts MVC 整合到 Spring 框架的方法。我将揭示每种方法的缺陷并且对比它们的优点。 一旦您了解到所有三种方法的作用，我将会向您展示一个令人兴奋的应用程序，这个程序使用的是这三种方法中我最喜欢的一种。<br /></p><p><a name="N100BF"><span class="atitle"><font face="Arial" size="4"><strong>三个小窍门</strong></font></span></a></p><p>接下来的每种整合技术（或者窍门）都有自己的优点和特点。我偏爱其中的一种，但是我知道这三种都能够加深您对 Struts 和 Spring 的理解。在处理各种不同情况的时候，这将给您提供一个广阔的选择范围。方法如下：</p><ul><li>使用 Spring 的 <code>ActionSupport</code> 类整合 Structs 
</li><li>使用 Spring 的 <code>DelegatingRequestProcessor</code> 覆盖 Struts 的 <code>RequestProcessor </code></li><li>将 Struts <code>Action</code> 管理委托给 Spring 框架 </li></ul><p><a name="N100E4"><span class="smalltitle"><strong><font face="Arial">装载应用程序环境</font></strong></span></a></p><p>无论您使用哪种技术，都需要使用 Spring 的 <code>ContextLoaderPlugin</code> 为 Struts 的 <code>ActionServlet</code> 装载 Spring 应用程序环境。就像添加任何其他插件一样，简单地向您的 struts-config.xml 文件添加该插件，如下所示：</p><p></p><table style="WIDTH: 664px; HEIGHT: 84px" cellspacing="0" cellpadding="5" width="664" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;plug-in className=
  "org.springframework.web.struts.ContextLoaderPlugIn"&gt;
    &lt;set-property property=
      "contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
 &lt;/plug-in&gt;
</font></code></pre></td></tr></tbody></table><p><a name="N10101"><span class="atitle"><font face="Arial" size="4"><strong>窍门 1. 使用 Spring 的 ActionSupport</strong></font></span></a></p><p>手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单，Spring 提供了一些帮助。为了方便地获得 Spring 环境，<code>org.springframework.web.struts.ActionSupport</code> 类提供了一个 <code>getWebApplicationContext()</code> 方法。您所做的只是从 Spring 的 <code>ActionSupport</code> 而不是 Struts <code>Action</code> 类扩展您的动作，如清单 1 所示：</p><br /><a name="N1011F"><b>清单 1. 使用 ActionSupport 整合 Struts</b></a><br /><table style="WIDTH: 665px; HEIGHT: 634px" cellspacing="0" cellpadding="5" width="665" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends ActionSupport {   <span class="boldcode"><strong>|(1)</strong></span>


  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    DynaActionForm searchForm = (DynaActionForm) form;
    String isbn = (String) searchForm.get("isbn");
		
    //the old fashion way
    //BookService bookService = new BookServiceImpl();
		
    ApplicationContext ctx = 
      getWebApplicationContext();    <span class="boldcode"><strong>|(2)</strong></span>
    BookService bookService = 
      (BookService) ctx.getBean("bookService");   <span class="boldcode"><strong>|(3)</strong></span>
        
  Book book = bookService.read(isbn.trim());

    if (null == book) {
      ActionErrors errors = new ActionErrors();
      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
        ("message.notfound"));
      saveErrors(request, errors);
      return mapping.findForward("failure") ;
  }

    request.setAttribute("book", book);
    return mapping.findForward("success");
  }
}
</font></code></pre></td></tr></tbody></table><br /><p>让我们快速思考一下这里到底发生了什么。在 (1) 处，我通过从 Spring 的 <code>ActionSupport</code> 类而不是 Struts 的 <code>Action</code> 类进行扩展，创建了一个新的 <code>Action</code>。在 (2) 处，我使用 <code>getWebApplicationContext()</code> 方法获得一个 <code>ApplicationContext</code>。为了获得业务服务，我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。</p><p>这种技术很简单并且易于理解。不幸的是，它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉 Spring，那么您必须重写代码。并且，由于 Struts 动作不在 Spring 的控制之下，所以它不能获得 Spring AOP 的优势。当使用多重独立的 Spring 环境时，这种技术可能有用，但是在大多数情况下，这种方法不如另外两种方法合适。<br /></p><p><a name="N10149"><span class="atitle"><font face="Arial" size="4"><strong>窍门 2. 覆盖 RequestProcessor</strong></font></span></a></p><p>将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 <code>org.springframework.web.struts.DelegatingRequestProcessor</code> 类来覆盖 Struts 的 <code>RequestProcessor</code> 处理程序，如清单 2 所示：</p><p><br /><a name="N1015F"><b>清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合</b></a><br /></p><table style="WIDTH: 665px; HEIGHT: 590px" cellspacing="0" cellpadding="5" width="665" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;

&lt;!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;

&lt;struts-config&gt;
 &lt;form-beans&gt;
    &lt;form-bean name="searchForm" 
      type="org.apache.struts.validator.DynaValidatorForm"&gt;
               &lt;form-property name="isbn"    type="java.lang.String"/&gt;
    &lt;/form-bean&gt;
  
  &lt;/form-beans&gt;

 &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;
     &lt;forward   name="welcome"                path="/welcome.do"/&gt;
     &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;
     &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;
 &lt;/global-forwards&gt;

 &lt;action-mappings&gt;
    &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;
    &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;
    &lt;action    path="/searchSubmit" 
               type="ca.nexcel.books.actions.SearchSubmit"
               input="/searchEntry.do"
               validate="true"
               name="searchForm"&gt;
              &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;
              &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;
    &lt;/action&gt;  

 &lt;/action-mappings&gt;

 &lt;message-resources parameter="ApplicationResources"/&gt;

 &lt;controller processorClass="org.springframework.web.struts.
   DelegatingRequestProcessor"/&gt; <span class="boldcode"><strong>|(1)</strong></span>

 &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
    &lt;set-property property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;
 &lt;/plug-in&gt;


 &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;
    &lt;set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
 &lt;/plug-in&gt;
 
&lt;/struts-config&gt;
</font></code></pre></td></tr></tbody></table><br /><p>我利用了 <code>&lt;controller&gt;</code> 标记来用 <code>DelegatingRequestProcessor</code> 覆盖默认的 Struts <code>RequestProcessor</code>。下一步是在我的 Spring 配置文件中注册该动作，如清单 3 所示：</p><p><br /><a name="N1017C"><b>清单 3. 在 Spring 配置文件中注册一个动作</b></a><br /></p><table style="WIDTH: 665px; HEIGHT: 183px" cellspacing="0" cellpadding="5" width="665" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
  "http://www.springframework.org/dtd/spring-beans.dtd"&gt;

&lt;beans&gt;
  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;

  &lt;bean name="/searchSubmit" 
    class="ca.nexcel.books.actions.SearchSubmit"&gt; <span class="boldcode"><strong>|(1)</strong></span>
     &lt;property name="bookService"&gt;
        &lt;ref bean="bookService"/&gt;
     &lt;/property&gt;
  &lt;/bean&gt;
&lt;/beans&gt;
</font></code></pre></td></tr></tbody></table><br /><p>注意：在 (1) 处，我使用名称属性注册了一个 bean，以匹配 struts-config 动作映射名称。<code>SearchSubmit</code> 动作揭示了一个 JavaBean 属性，允许 Spring 在运行时填充属性，如清单 4 所示：</p><p><br /><a name="N10191"><b>清单 4. 具有 JavaBean 属性的 Struts 动作</b></a><br /></p><table style="WIDTH: 663px; HEIGHT: 623px" cellspacing="0" cellpadding="5" width="663" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends Action {
	
  private BookService bookService;
  public BookService getBookService() {
    return bookService;
  }

  public void setBookService(BookService bookService) { <span class="boldcode"><strong>| (1)</strong></span>
    this.bookService = bookService; 
  } 

  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    DynaActionForm searchForm = (DynaActionForm) form;
    String isbn = (String) searchForm.get("isbn");
		
  Book book = getBookService().read(isbn.trim());  <span class="boldcode"><strong>|(2)</strong></span>

    if (null == book) {
      ActionErrors errors = new ActionErrors();
      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
      saveErrors(request, errors);
      return mapping.findForward("failure") ;
  }

      request.setAttribute("book", book);
      return mapping.findForward("success");
  }

}
</font></code></pre></td></tr></tbody></table><br /><p>在清单 4 中，您可以了解到如何创建 Struts 动作。在 (1) 处，我创建了一个 JavaBean 属性。<code>DelegatingRequestProcessor</code>自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理，并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在，所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。</p><p><code>DelegatingRequestProcessor</code> 方法的确比第一种方法好，但是仍然存在一些问题。如果您使用一个不同的 <code>RequestProcessor</code>，则需要手动整合 Spring 的 <code>DelegatingRequestProcessor</code>。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外，还有过一些使用一系列命令来代替 Struts <code>RequestProcessor</code> 的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。<br /></p><p><a name="N101B7"><span class="atitle"><font face="Arial" size="4"><strong>窍门 3. 将动作管理委托给 Spring</strong></font></span></a></p><p>一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 <code>struts-config</code> 动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下，所以它可以填充动作的 JavaBean 属性，并为应用诸如 Spring 的 AOP 拦截器之类的特性带来了可能。 </p><p>清单 5 中的 <code>Action</code> 类与清单 4 中的相同。但是 struts-config 有一些不同：</p><p><br /><a name="N101D0"><b>清单 5. Spring 整合的委托方法</b></a><br /></p><table style="WIDTH: 663px; HEIGHT: 601px" cellspacing="0" cellpadding="5" width="663" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;

&lt;!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;

&lt;struts-config&gt;
 &lt;form-beans&gt;
    &lt;form-bean name="searchForm" 
      type="org.apache.struts.validator.DynaValidatorForm"&gt;
               &lt;form-property name="isbn"    type="java.lang.String"/&gt;
    &lt;/form-bean&gt;
  
  &lt;/form-beans&gt;

 &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;
     &lt;forward   name="welcome"                path="/welcome.do"/&gt;
     &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;
     &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;
 &lt;/global-forwards&gt;

 &lt;action-mappings&gt;
    &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;
    &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;
    &lt;action    path="/searchSubmit" 
             type="org.springframework.web.struts.DelegatingActionProxy" <span class="boldcode"><strong>|(1)</strong></span>
             input="/searchEntry.do"
             validate="true"
             name="searchForm"&gt;
             &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;
             &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;
    &lt;/action&gt;  

 &lt;/action-mappings&gt;

 &lt;message-resources parameter="ApplicationResources"/&gt;


 &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
    &lt;set-property 
    property="pathnames" 
    value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;
 &lt;/plug-in&gt;


 &lt;plug-in 
    className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;
    &lt;set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
 &lt;/plug-in&gt;

 
&lt;/struts-config&gt;
</font></code></pre></td></tr></tbody></table><br /><p>清单 5 是一个典型的 struts-config.xml 文件，只有一个小小的差别。它注册 Spring 代理类的名称，而不是声明动作的类名，如（1）处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 <code>ContextLoaderPlugIn</code> 声明的环境。</p><p>将一个 Struts 动作注册为一个 Spring bean 是非常直观的，如清单 6 所示。我利用动作映射使用 <code>&lt;bean&gt;</code> 标记的名称属性（在这个例子中是 "<code>/searchSubmit</code>"）简单地创建了一个 bean。这个动作的 JavaBean 属性像任何 Spring bean 一样被填充： </p><p><br /><a name="N101F0"><b>清单 6. 在 Spring 环境中注册一个 Struts 动作</b></a><br /></p><table style="WIDTH: 661px; HEIGHT: 194px" cellspacing="0" cellpadding="5" width="661" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
 "http://www.springframework.org/dtd/spring-beans.dtd"&gt;

&lt;beans&gt;
  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;

  &lt;bean name="/searchSubmit"   
        class="ca.nexcel.books.actions.SearchSubmit"&gt;
     &lt;property name="bookService"&gt;
        &lt;ref bean="bookService"/&gt;
     &lt;/property&gt;
  &lt;/bean&gt;

&lt;/beans&gt;
</font></code></pre></td></tr></tbody></table><p><a name="N101F7"><span class="atitle"><font face="Arial" size="4"><strong>动作委托的优点</strong></font></span></a></p><p>动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring，不对代码作任何改变就可用于非 Spring 应用程序中。<code>RequestProcessor</code> 的改变不会影响它，并且它可以利用 Spring AOP 特性的优点。 </p><p>动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作，您就可以使用 Spring 给动作补充更强的活力。例如，没有 Spring 的话，所有的 Struts 动作都必须是线程安全的。如果您设置 <code>&lt;bean&gt;</code> 标记的 singleton 属性为“false”，那么不管用何种方法，您的应用程序都将在每一个请求上有一个新生成的动作对象。您可能不需要这种特性，但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如，当实例化 Struts 动作时，<code>&lt;bean&gt;</code> 标记的 init-method 属性被用于运行一个方法。类似地，在从容器中删除 bean 之前，destroy-method 属性执行一个方法。这些方法是管理昂贵对象的好办法，它们以一种与 Servlet 生命周期相同的方式进行管理。<br /></p><p><a name="N10210"><span class="atitle"><font face="Arial" size="4"><strong>拦截 Struts</strong></font></span></a></p><p>前面提到过，通过将 Struts 动作委托给 Spring 框架而整合 Struts 和 Spring 的一个主要的优点是：您可以将 Spring 的 AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts 动作，您可以用最小的代价处理横切关注点。</p><p>虽然 Spring 提供很多内置拦截器，但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts 动作。为了使用拦截器，您需要做三件事：</p><ol><li>创建拦截器。 
</li><li>注册拦截器。 
</li><li>声明在何处拦截代码。 </li></ol><p>这看起来非常简单的几句话却非常强大。例如，在清单 7 中，我为 Struts 动作创建了一个日志记录拦截器。 这个拦截器在每个方法调用之前打印一句话：</p><p><br /><a name="N10230"><b>清单 7. 一个简单的日志记录拦截器</b></a><br /></p><table style="WIDTH: 663px; HEIGHT: 161px" cellspacing="0" cellpadding="5" width="663" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package ca.nexcel.books.interceptors;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class LoggingInterceptor implements MethodBeforeAdvice {

   public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("logging before!");
    }
}
</font></code></pre></td></tr></tbody></table><br /><p>这个拦截器非常简单。<code>before()</code> 方法在拦截点中每个方法之前运行。在本例中，它打印出一句话，其实它可以做您想做的任何事。下一步就是在 Spring 配置文件中注册这个拦截器，如清单 8 所示：</p><p><br /><a name="N10242"><b>清单 8. 在 Spring 配置文件中注册拦截器</b></a><br /></p><table style="WIDTH: 660px; HEIGHT: 392px" cellspacing="0" cellpadding="5" width="660" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
  "http://www.springframework.org/dtd/spring-beans.dtd"&gt;

&lt;beans&gt;
  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;

  &lt;bean name="/searchSubmit" 
        class="ca.nexcel.books.actions.SearchSubmit"&gt;
     &lt;property name="bookService"&gt;
        &lt;ref bean="bookService"/&gt;
     &lt;/property&gt;
  &lt;/bean&gt;

  &lt;!--  Interceptors --&gt; 
  &lt;bean name="logger"    
    class="ca.nexcel.books.interceptors.LoggingInterceptor"/&gt; <span class="boldcode"><strong>|(1)</strong></span>

  &lt;!-- AutoProxies --&gt;
  &lt;bean name="loggingAutoProxy" 
        class="org.springframework.aop.framework.autoproxy.
          BeanNameAutoProxyCreator"&gt; <span class="boldcode"><strong>|(2)</strong></span>
    &lt;property name="beanNames"&gt;
          &lt;value&gt;/searchSubmit&lt;/valuesgt; <span class="boldcode"><strong>|(3)</strong></span>
    &lt;/property&gt;
    &lt;property name="interceptorNames"&gt;
        &lt;list&gt;
          &lt;value&gt;logger&lt;/value&gt; <span class="boldcode"><strong>|(4)</strong></span>
        &lt;/list&gt;
    &lt;/property&gt;
   &lt;/bean&gt;

&lt;/beans&gt;
</font></code></pre></td></tr></tbody></table><br /><p>您可能已经注意到了，清单 8 扩展了 清单6 中所示的应用程序以包含一个拦截器。具体细节如下：</p><ul><li>在 (1) 处，我注册了这个拦截器。 
</li><li>在 (2) 处，我创建了一个 bean 名称自动代理，它描述如何应用拦截器。还有其他的方法定义拦截点，但是这种方法常见而简便。 
</li><li>在 (3) 处，我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作，则只需要在 "beanNames" 下面创建附加的 <code>&lt;value&gt;</code> 标记。 
</li><li>在 (4) 处，当拦截发生时，我执行了在 (1) 处创建的拦截器 bean 的名称。这里列出的所有拦截器都应用于“beanNames”。 </li></ul><p>就是这样。就像这个例子所展示的，将您的 Struts 动作置于 Spring 框架的控制之下，为处理您的 Struts 应用程序提供了一系列全新的选择。在本例中，使用动作委托可以轻松地利用 Spring 拦截器提高 Struts 应用程序中的日志记录能力。<br /></p><p><a name="N10272"><span class="atitle"><font face="Arial" size="4"><strong>结束语</strong></font></span></a></p><p>在本文中，您已经学习了将 Struts 动作整合到 Spring 框架中的三种窍门。使用 Spring 的 <code>ActionSupport</code> 来整合 Struts（第一种窍门中就是这样做的）简单而快捷，但是会将 Struts 动作与 Spring 框架耦合在一起。如果您需要将应用程序移植到一个不同的框架，则需要重写代码。第二种解决方法通过委托 <code>RequestProcessor</code> 巧妙地解开代码的耦合，但是它的可扩展性不强，并且当 Struts 的 <code>RequestProcessor</code> 变成一系列命令时，这种方法就持续不了很长时间。第三种方法是这三种方法中最好的：将 Struts 动作委托给 Spring 框架可以使代码解耦，从而使您可以在您的 Struts 应用程序中利用 Spring 的特性（比如日志记录拦截器）。</p><p>三种 Struts-Spring 整合窍门中的每一种都被实现成一个完整可用的应用程序。</p><img src ="http://www.blogjava.net/rain1102/aggbug/70561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-19 16:41 <a href="http://www.blogjava.net/rain1102/articles/70561.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring+ibatis的applicationContext配置</title><link>http://www.blogjava.net/rain1102/articles/69853.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 15 Sep 2006 04:01:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/69853.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/69853.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/69853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/69853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/69853.html</trackback:ping><description><![CDATA[&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="<font color="#000000">dataSource</font>" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;<br />    &lt;property name="driverClassName"&gt;<br />      &lt;value&gt;net.sourceforge.jtds.jdbc.Driver&lt;/value&gt;<br />    &lt;/property&gt;<br />    &lt;property name="url"&gt;<br />      &lt;value&gt;jdbc:jtds:sqlserver://127.0.0.1:1433/Sample&lt;/value&gt;<br />    &lt;/property&gt;<br />    &lt;property name="username"&gt;<br />      &lt;value&gt;test&lt;/value&gt;<br />    &lt;/property&gt;<br />    &lt;property name="password"&gt;<br />      &lt;value&gt;changeit&lt;/value&gt;<br />    &lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"&gt;<br />    &lt;property name="configLocation"&gt;<br />      &lt;value&gt;SqlMapConfig.xml&lt;/value&gt;<br />    &lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;<br />    &lt;property name="dataSource"&gt;&lt;ref local="dataSource"/&gt;&lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean id="userDAO" class="net.xiaxin.dao.UserDAO"&gt;<br />    &lt;property name="dataSource"&gt;<br />      &lt;ref local="dataSource" /&gt;<br />    &lt;/property&gt;<br />    &lt;property name="sqlMapClient"&gt;<br />      &lt;ref local="sqlMapClient" /&gt;<br />    &lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;<br />    &lt;property name="transactionManager"&gt;<br />      &lt;ref bean="transactionManager" /&gt;<br />    &lt;/property&gt;<br />    &lt;property name="target"&gt;<br />      &lt;ref local="userDAO" /&gt;<br />    &lt;/property&gt;<br />    &lt;property name="transactionAttributes"&gt;<br />      &lt;props&gt;<br />        &lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&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 />&lt;/beans&gt;<br /><br /><font size="2">1． sqlMapClient节点<br />类似SessionFactory之与Hibernate，这里我们引入了针对ibatis SqlMap的SqlMapClientFactoryBean配置。SqlMapClient对于ibatis的意义类似于Session与Hibernate以及Connection与JDBC，这里的sqlMapClient节点实际上配置了一个sqlMapClient的创建工厂类。configLocation属性配置了ibatis映射文件的名称。<br />2． transactionManager节点<br />这里我们的transactionManager配置与之前JDBC示例中相同，都采用了DataSourceTransactionManager，这与Hibernate有些差异。<br />3． userDAO节点<br />对应的，UserDAO需要配置两个属性，sqlMapClient和DataSource，sqlMapClient将从指定的DataSource中获取数据库连接。</font><img src ="http://www.blogjava.net/rain1102/aggbug/69853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-15 12:01 <a href="http://www.blogjava.net/rain1102/articles/69853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring+Hibernate中的applicationContext.xml配制</title><link>http://www.blogjava.net/rain1102/articles/69851.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Fri, 15 Sep 2006 03:49:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/69851.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/69851.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/69851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/69851.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/69851.html</trackback:ping><description><![CDATA[&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 /> <br />&lt;beans&gt;<br /> &lt;bean id="<font color="#ff0000">dataSource</font>" class="<font color="#009933">org.apache.commons.dbcp.BasicDataSource</font>" destroy-method="close"&gt;<br />  &lt;property name="<font color="#ff0000">driverClassName</font>"&gt;<br />   &lt;value&gt;<font color="#009933">com.microsoft.jdbc.sqlserver.SQLServerDriver</font>&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#ff1493">url</font>"&gt;<br />   &lt;value&gt;<font color="#009900">jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=addressbook</font>&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="username"&gt;<br />   &lt;value&gt;sa&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="password"&gt;<br />   &lt;value&gt;sa&lt;/value&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /><font color="#800080"> &lt;!-- 配置sessionFactory, 注意这里引入的包的不同  --&gt;</font><font color="#7fffd4"><br /></font> &lt;bean id="<font color="#ff1493">sessionFactory</font>" class="<font color="#009933">org.springframework.orm.hibernate3.LocalSessionFactoryBean</font>"&gt;<br />  &lt;property name="<font color="#ff1493">dataSource</font>"&gt;<br />      &lt;ref local="<font color="#008000">dataSource</font>" /&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#ff1493">mappingResources</font>"&gt;<br />     &lt;list&gt;<br />        &lt;value&gt;<font color="#008000">com/netmarch/Hibernate/Userl.hbm.xml</font>&lt;/value&gt;<br />     &lt;/list&gt;<br />  &lt;/property&gt;<br />  &lt;property name="<font color="#ff1493">hibernateProperties</font>"&gt;<br />    &lt;props&gt;<br />      &lt;prop key="<font color="#ff1493">hibernate.dialect</font>"&gt;<font color="#008000">org.hibernate.dialect.SQLServerDialect</font>&lt;/prop&gt;<br />      &lt;prop key="<font color="#ff1493">hibernate.show_sql</font>"&gt;<font color="#008000">true</font>&lt;/prop&gt;<br />    &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;bean id="<font color="#ff1493">transactionManager</font>" class="<font color="#008000">org.springframework.orm.hibernate3.HibernateTransactionManager</font>"&gt;<br />  &lt;property name="sessionFactory"&gt;<br />   &lt;ref local="sessionFactory" /&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;bean id="userDAO" class="com.netmarch.dao.daoimp.UserDAOImp"&gt;<br />    &lt;property name="sessionFactory"&gt;<br />       &lt;ref local="sessionFactory" /&gt;<br />    &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;bean id="userDAOProxy" class="<font color="#008000">org.springframework.transaction.interceptor.TransactionProxyFactoryBean</font>"&gt;<br />    &lt;property name="transactionManager"&gt;<br />       &lt;ref bean="transactionManager" /&gt;<br />    &lt;/property&gt;<br />    &lt;property name="target"&gt;<br />       &lt;ref local="userDAO" /&gt;<br />    &lt;/property&gt;<br />    &lt;property name="<font color="#ff1493">transactionAttributes</font>"&gt;<br />      &lt;props&gt;<br />        &lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />        &lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />        &lt;prop key="is*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />     &lt;/props&gt;<br />   &lt;/property&gt;<br /> &lt;/bean&gt;<br /> <br /> &lt;bean name="/login" class="com.netmarch.struts.action.LoginAction" singleton="false"&gt;<br />    &lt;property name="userDAO"&gt;<br />       &lt;ref bean="userDAOProxy" /&gt;<br />    &lt;/property&gt;<br /> &lt;/bean&gt;<br />&lt;/beans&gt;<br /><br /><font size="2">1． SessionFactory的引入<br />Hibernate中通过SessionFactory创建和维护Session。Spring对SessionFactory的配置也进行了整合，无需再通过Hibernate.cfg.xml对SessionFactory进行设定。SessionFactory节点的mappingResources属性包含了映射文件的路径，list节点下可配置多个映射文件。hibernateProperties节点则容纳了所有的属性配置。<br />2． 采用面向Hibernate的TransactionManager实现：org.springframework.orm.hibernate.HibernateTransactionManager</font><img src ="http://www.blogjava.net/rain1102/aggbug/69851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-15 11:49 <a href="http://www.blogjava.net/rain1102/articles/69851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring 基础语义IoC &amp;DI </title><link>http://www.blogjava.net/rain1102/articles/69652.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Thu, 14 Sep 2006 07:28:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/articles/69652.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/69652.html</wfw:comment><comments>http://www.blogjava.net/rain1102/articles/69652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/69652.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/69652.html</trackback:ping><description><![CDATA[
		<font size="2">何谓控制反转（IoC = Inversion of Control），何谓依赖注入（DI = Dependency Injection）？<br />IoC，用白话来讲，就是由容器控制程序之间的关系，而非传统实现中，由程序代码直接操控。这也就是所谓“控制反转”的概念所在：控制权由应用代码中转到了外部容器，控制权的转移，是所谓反转。<br />相对IoC 而言，“依赖注入”的确更加准确的描述了这种古老而又时兴的设计理念。从名字上理解，所谓依赖注入，即组件之间的依赖关系由容器在运行期决定，形象的来说，即由容器动态的将某种依赖关系注入到组件之中。</font>
<img src ="http://www.blogjava.net/rain1102/aggbug/69652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2006-09-14 15:28 <a href="http://www.blogjava.net/rain1102/articles/69652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>