??xml version="1.0" encoding="utf-8" standalone="yes"?>色婷五月综激情亚洲综合,免费观看亚洲人成网站,亚洲 暴爽 AV人人爽日日碰http://www.tkk7.com/rendong/category/13646.htmlzh-cnFri, 02 Mar 2007 07:17:06 GMTFri, 02 Mar 2007 07:17:06 GMT60[转]用AcegiZ的Spring应用加把?/title><link>http://www.tkk7.com/rendong/archive/2006/12/24/89774.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Sun, 24 Dec 2006 12:05:00 GMT</pubDate><guid>http://www.tkk7.com/rendong/archive/2006/12/24/89774.html</guid><wfw:comment>http://www.tkk7.com/rendong/comments/89774.html</wfw:comment><comments>http://www.tkk7.com/rendong/archive/2006/12/24/89774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/rendong/comments/commentRss/89774.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/rendong/services/trackbacks/89774.html</trackback:ping><description><![CDATA[ <blockquote> <p>关键?J2EE Spring Acegi</p> <h3>[介]</h3> <p>对于一个典型的Web应用Q完善的认证和授权机制是必不可少的,在SpringFramework中,Juergen Hoeller提供的范例JPetStorel了一些这斚w的介l,但还q远不够QAcegi是一个专门ؓSpringFramework提供安全机制?目Q全UCؓAcegi Security System for SpringQ当前版本ؓ0.5.1Q就其目前提供的功能Q应该可以满绝大多数应用的需求?/p> <p>本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中用AcegiQ而不是详l介l其中的每个接口、每个类。注意,即对已l存在的Spring应用Q通过下面介绍的步骤,也可以马上n受到Acegi提供的认证和授权?/p> <p>[基础工作] <br />在你的Web应用的lib中添加Acegi下蝲包中的acegi-security.jar</p> <p>[web.xml] <br />实现认证和授权的最常用的方法是通过filterQAcegi亦是如此Q通常Acegi需要在web.xmld以下5个filter:</p> <p><filter> <br /><filter-name>Acegi Channel Processing Filter</filter-name> <br /><filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <br /><init-param> <br /><param-name>targetClass</param-name> <br /><param-value>net.sf.acegisecurity.securechannel.ChannelProcessingFilter</param-value> <br /></init-param> <br /></filter> <br /><filter> <br /><filter-name>Acegi Authentication Processing Filter</filter-name> <br /><filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <br /><init-param> <br /><param-name>targetClass</param-name> <br /><param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value> <br /></init-param> <br /></filter> <br /><filter> <br /><filter-name>Acegi HTTP BASIC Authorization Filter</filter-name> <br /><filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <br /><init-param> <br /><param-name>targetClass</param-name> <br /><param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value> <br /></init-param> <br /></filter> <br /><filter> <br /><filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name> <br /><filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class> <br /></filter> <br /><filter> <br /><filter-name>Acegi HTTP Request Security Filter</filter-name> <br /><filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <br /><init-param> <br /><param-name>targetClass</param-name> <br /><param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value> <br /></init-param> <br /></filter></p> <p>最先引赯惑的是net.sf.acegisecurity.util.FilterToBeanProxyQAcegi自己的文档上解释是: “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.”,如希望深I的话,ȝ看源代码应该不难理解?/p> <p>再下来就是添加filter-mapping了: <br /><filter-mapping> <br /><filter-name>Acegi Channel Processing Filter</filter-name> <br /><url-pattern>/*</url-pattern> <br /></filter-mapping> <br /><filter-mapping> <br /><filter-name>Acegi Authentication Processing Filter</filter-name> <br /><url-pattern>/*</url-pattern> <br /></filter-mapping> <br /><filter-mapping> <br /><filter-name>Acegi HTTP BASIC Authorization Filter</filter-name> <br /><url-pattern>/*</url-pattern> <br /></filter-mapping> <br /><filter-mapping> <br /><filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name> <br /><url-pattern>/*</url-pattern> <br /></filter-mapping> <br /><filter-mapping> <br /><filter-name>Acegi HTTP Request Security Filter</filter-name> <br /><url-pattern>/*</url-pattern> <br /></filter-mapping></p> <p>q里Q需要注意以下两点: <br />1) q几个filter的顺序是不能更改的,序不对无法正常工作; <br />2) 如果你的应用不需要安全传输,如httpsQ则”Acegi Channel Processing Filter”相兛_Ҏ释掉卛_Q?<br />3) 如果你的应用不需要Spring提供的远E访问机Ӟ如Hessian and BurlapQ将”Acegi HTTP BASIC Authorization <br />Filter”相兛_Ҏ释掉卛_?/p> <p>[applicationContext.xml] <br />接下来就是要dapplicationContext.xml中的内容了,从刚才FilterToBeanFactory的解释可以看出,真正的filter?<br />在Spring的applicationContext中管理:</p> <p>1) 首先Q你的数据库中必d有保存用户名和密码的tableQAcegi要求table的schema必须如下Q?/p> <p>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);</p> <p>2) d讉K你的数据库的datasource和Acegi的jdbcDaoQ如下:</p> <p><bean id=”dataSource?class=”org.springframework.jdbc.datasource.DriverManagerDataSource?gt; <br /><property name=”driverClassName?gt;<value>${jdbc.driverClassName}</value></property> <br /><property name=”url?gt;<value>${jdbc.url}</value></property> <br /><property name=”username?gt;<value>${jdbc.username}</value></property> <br /><property name=”password?gt;<value>${jdbc.password}</value></property> <br /></bean> <br /><bean id=”jdbcDaoImpl?class=”net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl?gt; <br /><property name=”dataSource?gt;<ref bean=”dataSource?></property> <br /></bean></p> <p>3) dDaoAuthenticationProvider:</p> <p><bean id=”daoAuthenticationProvider?class=”net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider?gt; <br /><property name=”authenticationDao?gt;<ref bean=”authenticationDao?></property> <br /><property name=”userCache?gt;<ref bean=”userCache?></property> <br /></bean></p> <p><bean id=”userCache?class=”net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache?gt; <br /><property name=”minutesToIdle?gt;<value>5</value></property> <br /></bean></p> <p>如果你需要对密码加密Q则在daoAuthenticationProvider中加入:<property name=”passwordEncoder?gt;<ref <br />bean=”passwordEncoder?></property>QAcegi提供了几U加密方法,详细情况可看?<br />net.sf.acegisecurity.providers.encoding</p> <p>4) dauthenticationManager:</p> <p><bean id=”authenticationManager?class=”net.sf.acegisecurity.providers.ProviderManager?gt; <br /><property name=”providers?gt; <br /><list> <br /><ref bean=”daoAuthenticationProvider?> <br /></list> <br /></property> <br /></bean></p> <p>5) daccessDecisionManager:</p> <p><bean id=”accessDecisionManager?class=”net.sf.acegisecurity.vote.AffirmativeBased?gt; <br /><property name=”allowIfAllAbstainDecisions?gt; <br /><value>false</value> <br /></property> <br /><property name=”decisionVoters?gt; <br /><list><ref bean=”roleVoter?></list> <br /></property> <br /></bean> <br /><bean id=”roleVoter?class=”net.sf.acegisecurity.vote.RoleVoter?></p> <p>6) dauthenticationProcessingFilterEntryPoint:</p> <p><bean id=”authenticationProcessingFilterEntryPoint?<br />class=”net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint?gt; <br /><property name=”loginFormUrl?gt;<value>/acegilogin.jsp</value></property> <br /><property name=”forceHttps?gt;<value>false</value></property> <br /></bean></p> <p>其中acegilogin.jsp是登陆页面,一个最单的d面如下Q?/p> <p><%@ taglib prefix=’c?uri=’http://java.sun.com/jstl/core?%> <br /><%@ page import=”net.sf.acegisecurity.ui.AbstractProcessingFilter?%> <br /><%@ page import=”net.sf.acegisecurity.AuthenticationException?%> <br /><html> <br /><head> <br /><title>Login</title> <br /></head></p> <p><body> <br /><h1>Login</h1> <br /><form action=?lt;c:url value=’j_acegi_security_check?>?method=”POST?gt; <br /><table> <br /><tr><td>User:</td><td><input type=’text?name=’j_username?gt;</td></tr> <br /><tr><td>Password:</td><td><input type=’password?name=’j_password?gt;</td></tr> <br /><tr><td colspan=??gt;<input name=”submit?type=”submit?gt;</td></tr> <br /><tr><td colspan=??gt;<input name=”reset?type=”reset?gt;</td></tr> <br /></table> <br /></form> <br /></body> <br /></html></p> <p>7) dfilterInvocationInterceptor:</p> <p><bean id=”filterInvocationInterceptor?<br />class=”net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor?gt; <br /><property name=”authenticationManager?gt; <br /><ref bean=”authenticationManager?> <br /></property> <br /><property name=”accessDecisionManager?gt; <br /><ref bean=”accessDecisionManager?> <br /></property> <br /><property name=”objectDefinitionSource?gt; <br /><value> <br />CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON <br />\A/sec/administrator.*\Z=ROLE_SUPERVISOR <br />\A/sec/user.*\Z=ROLE_TELLER <br /></value> <br /></property> <br /></bean></p> <p>q里h意,要objectDefinitionSource中定义哪些页面需要权限访问,需要根据自q应用需求进行修改,我上面给?<br />的定义的意思是q样的: <br />a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求\径时全部转换为小?<br />b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能讉K/sec/administrator*的页?<br />c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用h能访?sec/user*的页?/p> <p>8) dsecurityEnforcementFilter:</p> <p><bean id=”securityEnforcementFilter?class=”net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter?gt; <br /><property name=”filterSecurityInterceptor?gt; <br /><ref bean=”filterInvocationInterceptor?> <br /></property> <br /><property name=”authenticationEntryPoint?gt; <br /><ref bean=”authenticationProcessingFilterEntryPoint?> <br /></property> <br /></bean></p> <p>9) dauthenticationProcessingFilter:</p> <p><bean id=”authenticationProcessingFilter?<br />class=”net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter?gt; <br /><property name=”authenticationManager?gt; <br /><ref bean=”authenticationManager?> <br /></property> <br /><property name=”authenticationFailureUrl?gt; <br /><value>/loginerror.jsp</value> <br /></property> <br /><property name=”defaultTargetUrl?gt; <br /><value>/</value> <br /></property> <br /><property name=”filterProcessesUrl?gt; <br /><value>/j_acegi_security_check</value> <br /></property> <br /></bean> <br />其中authenticationFailureUrl是认证失败的面?/p> <p>10) 如果需要一些页面通过安全通道的话Q添加下面的配置:</p> <p><bean id=”channelProcessingFilter?class=”net.sf.acegisecurity.securechannel.ChannelProcessingFilter?gt; <br /><property name=”channelDecisionManager?gt; <br /><ref bean=”channelDecisionManager?> <br /></property> <br /><property name=”filterInvocationDefinitionSource?gt; <br /><value> <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 /></value> <br /></property> <br /></bean></p> <p><bean id=”channelDecisionManager?class=”net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl?gt; <br /><property name=”channelProcessors?gt; <br /><list> <br /><ref bean=”secureChannelProcessor?> <br /><ref bean=”insecureChannelProcessor?> <br /></list> <br /></property> <br /></bean> <br /><bean id=”secureChannelProcessor?class=”net.sf.acegisecurity.securechannel.SecureChannelProcessor?> <br /><bean id=”insecureChannelProcessor?class=”net.sf.acegisecurity.securechannel.InsecureChannelProcessor?></p> <p>[~少了什么?] <br />Acegi目前提供了两U”secure object”,分别寚w面和Ҏq行安全认证理Q我q里介绍的只是利?<br />FilterSecurityInterceptor对访问页面的权限控制Q除此之外,Acegiq提供了另外一个Interceptor?<br />MethodSecurityInterceptorQ它l合runAsManager可实现对对象中的Ҏ的权限控Ӟ使用Ҏ可参看Acegi自带的文?<br />和contact范例?/p> <p>[最后要说的] <br />本来以ؓ只是说明如何使用Acegi而已Q应该非常简单,但真正写h才发现想要条理清楚的理顺所有需要的beanq是?<br />困难的,但愿我没有遗漏太多东西,如果我的文章有什么遗漏或错误的话Q还请参看Acegi自带的quick-start范例Q但?<br />注意Q这个范例是不能直接拿来用的?/p> <p>原文在这里:</p> <p>Trackback: <a >http://tb.blog.csdn.net/TrackBack.aspx?PostId=54881</a></p> </blockquote> <img src ="http://www.tkk7.com/rendong/aggbug/89774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/rendong/" target="_blank">rendong</a> 2006-12-24 20:05 <a href="http://www.tkk7.com/rendong/archive/2006/12/24/89774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ThreadLocal的几U误?转蝲 原作者jspark)http://www.tkk7.com/rendong/archive/2006/08/05/61883.htmlrendongrendongFri, 04 Aug 2006 16:45:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/05/61883.htmlhttp://www.tkk7.com/rendong/comments/61883.htmlhttp://www.tkk7.com/rendong/archive/2006/08/05/61883.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61883.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61883.html误解

 一、ThreadLocal是javaU程的一个实?br />      ThreadLocal的确是和javaU程有关Q不q它q不是javaU程的一个实玎ͼ它只是用来维护本地变量。针Ҏ个线E,提供自己的变量版本,主要是ؓ了避免线E冲H,每个U程l护自己的版本。彼此独立,修改不会影响到对斏V?

 二、ThreadLocal是相对于每个session?/p>

        ThreadLocal֐思义Q是针对U程。在java web~程上,每个用户从开始到会话l束Q都有自q一个session标识。但是ThreadLocalq不是在会话层上。其实,Threadlocal是独立于用户session的。它是一U服务器端行为,当服务器每生成一个新的线E时Q就会维护自qThreadLocal。对于这个误解,个h认ؓ应该是开发h员在本地Z一些应用服务器试的结果。众所周知Q一般的应用服务器都会维护一套线E池Q也是_对于每次讉KQƈ不一定就新生成一个线E。而是自己有一个线E缓存池。对于访问,先从~存池里面找到已有的U程Q如果已l用光,才去新生成新的线E。所以,׃开发h员自己在试Ӟ一般只有他自己在测Q这h务器的负担很,q样D每次讉K可能是共用同样一个线E,D会有q样的误解:每个session有一个ThreadLocal

 三、ThreadLocal是相对于每个U程的,用户每次讉K会有新的ThreadLocal

  理论上来_ThreadLocal是的是相对于每个线E,每个U程会有自己的ThreadLocal。但是上面已l讲刎ͼ一般的应用服务器都会维护一套线E池。因此,不同用户讉KQ可能会接受到同LU程。因此,在做ZTheadLocalӞ需要}慎,避免出现ThreadLocal变量的缓存,D其他U程讉K到本U程变量

 四、对每个用户讉KQThreadLocal可以多用
        可以_ThreadLocal是一把双刃剑Q用得来的话可以起到非常好的效果。但是,ThreadLocal如果用得不好Q就会跟全局变量一栗代码不能重用,不能独立试。因为,一些本来可以重用的c,现在依赖于ThreadLocal变量。如果在其他没有ThreadLocal场合Q这些类变得不可用了。个得ThreadLocal用得很好的几个应用场合,值得参?/p>

  1、存攑ֽ前session用户Qquake want的jert

  2、存放一些context变量Q比如webwork的ActionContext

  3、存放sessionQ比如Spring hibernate orm的session



rendong 2006-08-05 00:45 发表评论
]]>
Spring中的destroy-method="close"(转自JavaEye)http://www.tkk7.com/rendong/archive/2006/08/04/61797.htmlrendongrendongFri, 04 Aug 2006 09:14:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/04/61797.htmlhttp://www.tkk7.com/rendong/comments/61797.htmlhttp://www.tkk7.com/rendong/archive/2006/08/04/61797.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61797.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61797.htmlI竟Spring在何时调用destroy-method="close" q个Ҏclose()呢?l于借助JavaEye扑ֈ了答案,原来如果Spring不在Web Container或是EJB Container中的时候,q个Ҏq是需要我们自己来调用的,具体是调用BeanFactory的destroySingletons()ҎQ文档上的“自动调用”这几个字真是害我不呀Q原来自动也是通过Web Container或是EJB Container才可以自动,具体做法是要实现ServletContextListenerq个接口QSpring中已l有具体的实CQ?/font>
 
publicclass ContextLoaderListener implements ServletContextListener { 
        private ContextLoader contextLoader; 
       
/**
        * Initialize the root web application context.
        */

        publicvoid contextInitialized(ServletContextEvent event){
                this.contextLoader = createContextLoader();
                this.contextLoader.initWebApplicationContext(event.getServletContext());
        } 
       
/**
        * Create the ContextLoader to use. Can be overridden in subclasses.
        * @return the new ContextLoader
        */

        protected ContextLoader createContextLoader(){
                returnnew ContextLoader();
        } 
       
/**
        * Return the ContextLoader used by this listener.
        */

        public ContextLoader getContextLoader(){
                return contextLoader;
        } 
       
/**
        * Close the root web application context.
        */

        publicvoid contextDestroyed(ServletContextEvent event){
                this.contextLoader.closeWebApplicationContext(event.getServletContext());
        }

}
当tomcat关闭的时候会自动调用contextDestroyed(ServletContextEvent event)q个Ҏ。在看一下contextLoader的closeWebApplicationContextҎQ?
 
publicvoid closeWebApplicationContext(ServletContext servletContext)throws ApplicationContextException {
                servletContext.log("Closing root WebApplicationContext");
                Object wac = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
                if(wac instanceof ConfigurableApplicationContext){
                        ((ConfigurableApplicationContext) wac).close();
                }
        }
AbstractApplicationContext.Closeq个Ҏ是要你自p用的Q在E序要结束的时候保证调用这个closeҎQ在q里的话是由Listener来保证tomcat退出的时候调用closeҎ?
AbstractApplicationContext.Close的代?Q?/font>
 
publicvoid close(){
                logger.info("Closing application context [" + getDisplayName() + "]");

                // Destroy all cached singletons in this context,
                // invoking DisposableBean.destroy and/or "destroy-method".
                getBeanFactory().destroySingletons()
                // publish corresponding event
                publishEvent(new ContextClosedEvent(this));
        }

最l还是调用到了getBeanFactory().destroySingletons(); 看来Q没有容器,我们q是需要自己来搞定q个Ҏ的调用的 Q?/font>



rendong 2006-08-04 17:14 发表评论
]]>
在Struts和Hibernate之间搭v桥梁 --zt (?http://www.tkk7.com/rendong/archive/2006/08/02/61268.htmlrendongrendongTue, 01 Aug 2006 17:01:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/02/61268.htmlhttp://www.tkk7.com/rendong/comments/61268.htmlhttp://www.tkk7.com/rendong/archive/2006/08/02/61268.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61268.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61268.html 摘要

Hibernate和struts是当前市面上几个最行的开源的库之一。它们很有效率,是程序员在开发Java企业应用Q挑选几个竞争的库的首选。虽然它们经常被一起应用,但是Hibernate的设计目标ƈ不是和Struts一起用,而Struts在Hibernate诞生好多q之前就发布了。ؓ了让它们在一起工作,仍然有很多挑战。这文章点明了Struts和Hibernate之间的一些`沟,其关系到面向对象徏模方面。文章也描述了如何在两者间搭v桥梁Q给Z一个基于扩展Struts的解x案。所有的ZStruts和Hibernate构徏的Web应用都能从这个通用的扩展中L?br />
在Hibernate in ActionQManning,2004十月Q这本书里,作者Christian Bauer和Gavin King揭示了面向对象世界的模型和关pL据模型,两个世界的范例是不一致的。Hibernate非常成功地在存储?persistence Layer)两者粘合在一赗但是领域模?domain model)(也就是Model-View-Controller的model layer)和HTML面(MVC的View Layer)仍然存在不一致。在q篇文章中,我们检查这U不一_q且探烦解决的方案?br />
范例不一致的再发?/span>

让我们先看一个经典的parent-child关系例子Q看下面的代码)Qproduct和category。Categorycd义了一个类型ؓlong的标C符id和一个类型ؓString的属性name。ProductcM有一个类型ؓlong的标C符id和一个类型ؓCategory的属性categoryQ表CZ多对一的关p(也就是说很多product可以属于一个Category)

						/**
* @hibernate.class table="CATEGORY"
*/
public class Category {
   private Long id;

   private String name;

   /**
    * @hibernate.id generator-class="native" column="CATEGORY_ID"
    */
   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   /**
    * @hibernate.property column="NAME"
    */
   public String getName() {
      return name;
   }

   public void setName(Long name) {
      this.name = name;
   }
}

/**
* @hibernate.class table="PRODUCT"
*/
public class Product {
   private Long id;
   private Category category;

   /**
    * @hibernate.id generator-class="native" column="PRODUCT_ID"
    */
   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   /**
    * @hibernate.many-to-one
    * column="CATEGORY_ID"
    * class="Category"
    * cascade="none"
    * not-null="false"
    */
   public Category getCategory() {
      return category;
   }

   public void setCategory(Category category) {
      this.category = category;
   }
}



我们希望一个product可以被更改categoryQ所以我们的HTML提供了一个下拉框列出所有Category?br />
						<select name="categoryId">
   <option value="">No Category</option>
   <option value="1">Category 1</option>
   <option value="2">Category 2</option>
   <option value="3">Category 3</option>
</select>



q里我们看出了两者的不一_在Product领域对象里,category属性是CategorycdQ但是ProductForm只有一个类型ؓlong的categoryId。这U不匚w不但增加了不一_而且D了不必要的代码进行primitive type的标C符和对应的对象之间的{换?br />
q种不一致部分是׃HTML Form自己引v的:它只代表了一U关pL型,不能代表面向对象的模型。面向对象和关系模型的不一致在存储层由对象关系映射(O/RM)解决。但是类似的问题在表C层(view layer)仍然存在。解决的关键是让他们一h~地工作?br />
Struts的功能和局?/span>

q运的是QStruts能够生成和解释内嵌的对象属性。Category下拉框可以用Struts page-construction(html) tag libraryQ?br />
						<html:select property="category.id">
   <option value="">No Category</option>
   <html:options collection="categories" property="id" labelProperty="name"/>
</html:select>


我们假设categories是Category对象的一个list。所以现在我们要修改ProductFormQ让它变得更加“面向对象”,我们要修改ProductForm的categoryIdQ改成类型ؓCategory的category。这U改变会D在Product和ProductForm之间复制属性的工作更加J琐Q因Z者有相同的属性?br />
						public class ProductForm extends ActionForm {
     private Long id;
     private Category category;
     ...
}



当我们完成剩余的Struts Action, configuration, validator, jsp, hibernate层后Q开始测试,我们马上在访问ProductForm.category.id旉CNullPointerException。这是预料中的!因ؓProductForm.categoryq没有被讄Q同ӞHibernate也会多对一所联系的对象引用设为空Q如果database field为空指)Q译者:q里指Hiberateproduct.category为NullQ如果该Product没有联系CQ何category)。Struts要求所有的对象在显C?生成HTML Form)和传?提交HTML FORM)之前被徏立?br />
让我们看看如何用ActionForm.reset()来架h梁?br />
Qƈ非如此)臭名昭著的Struts ActionForm

在我W一个星期接触Struts的时候,我最大的一个疑问就是:Z么我必须为Properties, getterҎ, setterҎ保持几乎完全相同的两份copy, 一份在ActionForm Bean, 一份在DomainObject。这个繁琐的步骤成了StrutsC֌最主要的抱怨之一?br />
以我的观点,ActionForm存在有原因的。首先,它们可以区别于Domain Object因ؓ他们但当了不同的角色。在MVC模式下,Domain Object是Model层的一个部分,ActionForm是View层的。因为Webpage的Field和Database的Field可能不一P某些特制的{换是常见的。第二,ActionForm.validate()Ҏ可以定义非常好用的验证规则。第三,可能有其他的Q特定的View行ؓQ但是又不想在domain layer实现Q特别当persistence framework来管理domain object的时候?br />
提交Form

让我们来用ActionForm内有的方?reset()-来解决view和model之间的不一致。这个reset()Ҏ是在ActionForm在被Struts Controller Servlet处理request时候复制ActionForm属性之前调用的。这个方法最常见的用是Qcheckbox必须被显式地设ؓfalseQ让没有被选中的checkbox被正识别。Reset()也是一个初始化用于view rending对象的合适地斏V代码看h是这LQ?br />
						public class ProductForm extends ActionForm {
     private Long id;
     private Category category;
     ...
     public void reset(ActionMapping mapping, HttpServletRequest request)
     {
        super.reset( mapping, request );
        if ( category == null ) { category = new Category(); }
     }
}



Struts在用用h交的值填写ProductForm之前QStruts会调用reset()Q这样category属性将会被初始化。请注意Q你必须查category看它是不是nullQ后面我们会讨论q个?br />
~辑Form

到目前ؓ止,我们已经解决了form提交时候的问题。但是当我们在生成form面的时候呢QHtml:select tag也希望有一个非I的引用Q所以我们将在form生成面之前调用reset()。我们在actionc里加入了一?

						public class EditProductAction extends Action {
     public final ActionForward execute( ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response ) throws Exception
     {
        ...
        Product product = createOrLoadProduct();
        ProductForm productForm = (ProductForm)form;
        PropertyUtils.copyProperties( productForm, product );
        productForm.reset( mapping, request );
        ...
     }
}



我假设读者已l对actioncdJakarta commons Beanutils包非常熟悉了。CreateOrLoadProduct()建立了一个新的Product实例或者从数据库里载入一个已有的实例Q具体取决于q个action是徏立或者修改Product的。ProductForm被赋值后Q译者:也就是调用PropertyUtils.copyProperties后)QproductForm.category已经从Product.category复制q来了(译者:实际上只是复制了category对象引用Qƈ没有开销Q,然后QProductFormp用来生成面了。我们同时也必须保证Q不覆盖已经被Hibernate载入的对象,所以我们必L?category)是不是ؓnull?br />
因ؓreset()Ҏ是在ActionForm中定义的Q我们可以把上述代码攑օ一个superclassQ比如CommonEditActionQ来处理q些事情Q?br />    
						      Product product = createOrLoadProduct();
        PropertyUtils.copyProperties( form, product );
        form.reset( mapping, request );


如果你需要一个只ȝForm, 你有两个选择: W一查所联系的jsp对象是不是null, W二复制domain对象到ActionForm之后调用Reset()

保存domain对象

我们解决了提交Form和生成Form面的问? 所以Struts可以满了。但是Hibernate呢?当用户选择了一个null ID option ?在我们的例子中“no category”option- q且提交form, productForm.category指向一个新建立的hibernate对象Qid为null。当category属性从ProductForm复制到Hibernate控制的Product对象q且存储ӞHibernate会抱怨product.category是一个时对象,需要在Product存储前先被存储。当Ӟ我们知道它是NullQƈ且不需要被存储。所以我们需要将product.category|ؓNullQ然后Hibernatep存储Product了(译者:在这U情况下Q数据库product.category被设成空|。我们也不希望改变Hibernate的工作方式,所以我们选择在复制到Domain对象之前清理q些临时对象Q我们在ProductForm中加了一个方?

						public class ProductForm extends ActionForm {
     private Long id;
     private Category category;
     ...
     public void reset(ActionMapping mapping, HttpServletRequest request) {
        super.reset( mapping, request );
        if ( category == null ) { category = new Category(); }
     }

     public void cleanupEmptyObjects() {
        if ( category.getId() == null ) { category = null; }
     }
}



我们在copyProperties之前清理掉这些时对象,所以如果ProductForm.category只是用来放Null的,则将ProductForm.category|ؓNull。然后Domain对象的category也会被设成null:

						public class SaveProductAction extends Action {
     public final ActionForward execute( ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response ) throws Exception
     {
        ...
        Product product = new Product();
        ((ProductForm)form).cleanupEmptyObjects();
        PropertyUtils.copyProperties( product, form );
        SaveProduct( product );
        ...
     }
}



一对多关系

我还没有解决Category到Product的一对多关系。我们把它加入到Category的Metadata中:

						public class Category {
     ...
     private Set products;
     ...

     /**
      * @hibernate.set
      * table="PRODUCT"
      * lazy="true"
      * outer-join="auto"
      * inverse="true"
      * cascade="all-delete-orphan"
      *
      * @hibernate.collection-key
      * column="CATEGORY_ID"
      *
      * @hibernate.collection-one-to-many
      * class="Product"
      */
     public Set getProducts() {
        return products;
     }

     public void setProducts(Set products) {
        this.products = products;
     }
}


注意Q?/strong>Hibernate的cascade属性ؓall-delete-orphan表明QHibernate需要在存储包含的Category对象时候,自动存储Product对象。和parent对象一起存储child对象的情况ƈ不常见,常见的是Q分别控制child的存储和parent的存储。在我们的例子中Q我们可以容易地做到q一点,如果我们允许用户在同一个html page~辑Category和ProductS。用set表示Products是非常直观的Q?br />
						public class CategoryForm extends ActionForm {
     private Set productForms;
     ...
     public void reset(ActionMapping mapping, HttpServletRequest request) {
        super.reset( mapping, request );

        for ( int i = 0; i < MAX_PRODUCT_NUM_ON_PAGE; i++ ) {
           ProductForm productForm = new ProductForm();
           productForm.reset( mapping, request );
           productForms.add( productForm );
        }
     }

     public void cleanupEmptyObjects() {
        for ( Iterator i = productForms.iterator(); i.hasNext(); ) {
           ProductForm productForm = (ProductForm) i.next();
           productForm.cleanupEmptyObjects();
        }
     }
}



更进一?/strong>
我们已经可以察看,~辑,提交forms,q且存储相关的objects,但是为所有的ActionFormcd义CleanupEmptyObjects()和reset()Ҏ是个累赘。我们将用一个抽象的ActionForm来完成协助完成这些工作?br />
作ؓ通用的实玎ͼ我们必须遍历所有的Hibernate理的domain对象Q发C们的identifierQƈ且测试id倹{幸q的是:org.hibernate.metadata包已l有两个Utilityc能取出domain对象的元数据。我们用ClassMetadatacL查这个object是不是Hibernate理的。如果是Q我们把它们的id Value取出来。我们用了Jakarta Commons Beanutils包来协助JavaBean元数据的操作?br />
						import java.beans.PropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.metadata.ClassMetadata;

public abstract class AbstractForm extends ActionForm {
   public void reset(ActionMapping mapping, HttpServletRequest request) {
      super.reset( mapping, request );

      // Get PropertyDescriptor of all bean properties
      PropertyDescriptor descriptors[] =
         PropertyUtils.getPropertyDescriptors( this );

      for ( int i = 0; i < descriptors.length; i++ ) {
         Class propClass = descriptors.getPropertyType();

         ClassMetadata classMetadata = HibernateUtil.getSessionFactory()
            .getClassMetadata( propClass );

         if ( classMetadata != null ) {   // This is a Hibernate object
            String propName = descriptors.getName();
            Object propValue = PropertyUtils.getProperty( this, propName );

            // Evaluate property, create new instance if it is null
            if ( propValue == null ) {
               PropertyUtils.setProperty( this, propName, propClass.newInstance() );
            }
         }
      }
   }

   public void cleanupEmptyObjects() {
      // Get PropertyDescriptor of all bean properties
      PropertyDescriptor descriptors[] =
      PropertyUtils.getPropertyDescriptors( this );

      for ( int i = 0; i < descriptors.length; i++ ) {
         Class propClass = descriptors.getPropertyType();
         ClassMetadata classMetadata = HibernateUtil.getSessionFactory()
            .getClassMetadata( propClass );

         if ( classMetadata != null ) {   // This is a Hibernate object
            Serializable id = classMetadata.getIdentifier( this, EntityMode.POJO );

            // If the object id has not been set, release the object.
            // Define application specific rules of not-set id here,
            // e.g. id == null, id == 0, etc.
            if ( id == null ) {
               String propName = descriptors.getName();
               PropertyUtils.setProperty( this, propName, null );
            }


         }
      }
   }
}


Z让代码可读,我们省略了Exception的处理代码?br />
我们的新AbstractFormcMStruts的ActionFormcȝ承,q且提供了通用行ؓQreset和cleanup多对一兌对象。当q个关系是相反的话(也就是一对多关系Q,那么每个例子会有所不同Q类似在Abstractc里实现是比较好的办法?br />
ȝ

Struts和Hibernate是非常流行和强大的框Ӟ他们可以有效地相互合作,q且弥补domain模型和MVC视图(view)之间的差别。这文章讨Z个解决Struts/Hibernate Project的通用的方案,q且不需要大量修改已l有的代码?/font>

rendong 2006-08-02 01:01 发表评论
]]>
spring配置文g??http://www.xin7dian.com/simple/index.php?t146.html)http://www.tkk7.com/rendong/archive/2006/08/02/61267.htmlrendongrendongTue, 01 Aug 2006 16:57:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/02/61267.htmlhttp://www.tkk7.com/rendong/comments/61267.htmlhttp://www.tkk7.com/rendong/archive/2006/08/02/61267.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61267.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61267.html    但Spring MVC+hibernate的Sample如Appfuse的代码却不得最z优好读,如果在自q目中l发挥我们最擅长的依L葫芦大法Q美好愿望未必会实现?
     所以,Pramatic_不灭。这个系列就是探L适合自己的Spring+Hibernate模式?br />    
                              I-配置文g?/strong>

     我厌倦一切配|文件繁重的框架?
     最好的情况是,框架提供极端灉|复杂的配|方式,但只在你需要的时?/strong>?br /> 
     Spring提供了三U可能来化XML。随着国内用户水^的提高,q些基本的简化技巧大安已掌握?br />     大家可以直接看第3Q第4?-Spring 1.2, Spring 2.0的后l改q?br />

1.1.autowire="byName" /"byType"

     假设Controller有一个属性名为customerDAOQSpring׃在配|文仉查找有没有名字ؓCustomerDAO的bean, 自动为Controller注入?br />     如果bean有两个属性,一个想默认注入Q一个想自定义,只要讑֮了autowireQ然后显式的声明那个惌定义的,可以达到要求。这应了需求,在需要特别配|的时候就提供配置Q否则给我一个默认注入?br />
     q有一个更懒的地方Q在最最栚w?lt;beans>节点写一句default-autovwrie="byName"Q可以让文g里的所有bean 都默认autowrie?br />    不过Rod认ؓ开发期可以q样Q但Production Server上不应该使用Autowire。而我觉得那些自定义一ơ的地方比如TranscationManager应该详细定义Q而Dao,Controllerq种大量重复定义的bean可以偷Ҏ了?/p>

1.2.<bean>节点之间抽象公共定义?Inner Bean

    q太方便懒h了,想不C个独立的XML节点都可以玩l承和派生,子节Ҏ有父节点的全部属性?br />    最好用的地方就是那个Transtion Proxy的定义。先定义一个又长又冗的父类Q然后用子类ȝ承它?br />   
    另外Q还有一个Inner Bean的机Ӟ可以把DAO写成Proxy的内部类。ؓ什么要写成内部c?Z让Proxy冒名替它去让Controller Autowire?详见后面的示?

1.3. 宽松的配|? To XML or Not to XML 
    据说Spring比Struts的配|宽松了很多Q这q人把东西从配|文件中撤回原码中的Z?br />    不赞成什么都往配置文g里晒Q造成了Rich Information的配|文Ӟ修改或者查看的时候,要同时打开配置文g和原码才能清楚一切?
    而我希望配置文g集中做一些整体的配置Q还有框架必ȝ、无需理的冗余代码。而一些细节的变化不大的配|和逻辑Q就量别往里塞了。因此,Success/Fail View 的配|,不徏议放在里面?

2.化后的配|文?/strong>

1.Controller只剩下一?/p>

<bean name="customerController" class="org.springside.bookstore.web.CustomerController" autowire="byName"/>

2.DAO也只剩一?/p>

<bean id="customerDAO" class="org.springside.bookstore.dao.CustomerDao"/>

3.Servicecd剩下5?

  <bean id="customerManager" parent="baseTxService">
        
<property name="target">
            
<bean class="org.springside.bookstore.service.CustomerManager"/>
        
</property>
    
</bean>

3.Spring 1.2后xml语法?br />
 
最主要的简化是把属性值和引用bean?strong>子节?/strong>变回?strong>属性?/strong>Q对不喜Ƣautowire的兄弟比较有用?br /> 当然Q如果value要CDATA的时候还是要用子节点。另外,list的值可以用I格隔开也比较实用?br />

1.属性?br />
  <property name="foo">
     
<value>fooValue</value>
  </property>
  化ؓ
  <property name="foo" value="fooValue"/>

2.引用 bean
<property name="foo">
   
<ref bean="fooBean">
</property>
化ؓ
<property name="foo" ref="fooBean"/>


3. list可以化ؓI格分开的字W串
 
<property name="myFriendList">
  
<list>
     
<value>gigix</value>
        <value>wuyu</value>
  
</list>
</property>
化ؓ
<property name="myFriendList" value="gigix wuyu"/>
   
  
4.Spring 2.0来了
   如果没什么外力刺ȀQspring xml 可能p样不会变了。但现在xml成了q街老鼠Q被ror的默认配|和JDK5的annotation逼得不行Q当然就要l求变?br />   比如有好事者认为,节点名必Mbean打头Q附加一个属性id来表Cbean名;属性值必L一个property子节点,子节点上有个属性name来表C属性名Q是l机器看的很不直观的东西?
<bean id="customerDAO" class="org.springside...CustomerDAO">
 
<property name="maxCount" value="10">
</bean>

lh看的东西应该写?
<customerDAO class="org.springside....CustomerDAO" maxCount="10"/>

Spring 2.0正用schema实现cM的语法,具体L它的JPetStore sample?br />
5.使用Spring自带的DTD使编辑器Smart.

    如果没有用Eclipse的Spring插gQ那臛_也要使用spring自带的dtd使XML~辑器smart一些,能够自动Z生成属?判断节点/属性名U有没有拼错{?br />
6.q有更变态的化配|方?/strong>
    比如autoproxyQ不q我觉得更简化就不可控了Q所以没有采用?br />
因ؓSpring自带的sampleL们的实际目很远Q所以官方一点的model层模式展现就靠Appfuse了?br />    但Appfuse的model层d有一个DAO接口、一个DAOImplcR一个Service接口、一个ServiceImplcR一个DataObject.....大概只有受惯了虐待的人才会欣然接受吧?br />    另外QDomain-Driven逢初一、十五也会被拿出来讨Z遍?br />
    其实无论什么模式,都不q是一Uh为的划分、抽象和装。只要在团队里理解一_自我感觉优雅p了?br />     我的是,一开始DO和Manager一生一旦包演全场,DO作ؓU数据蝲体,而ManagercL|商业方法,用getHibernateTemplate()直接讉K数据库,不强制基于接口编E。当某天pȝ复杂C直觉上需要将DAO层和Service层分开Ӟ再分开好了?br />
    1.DataObjectc?br />     好听点也可以叫Domain Object。Domain Driven  Development虽然׃hQ但因ؓJava下的ORM框架都是ZData Mapper模式的,没有Ruby On Rails中那UActive Recorder的模式。所以,q是压下了这个欲望,Data ObjectUa作一个数据蝲体,而把数据库访问与商业逻辑操作l一攑ֈManagercM?br />
    2.Managerc?/font>
    我的ManagercLAppfuse中DAOcMServicecȝl合体,因ؓQ?br />
    2.1 不想使用UDAO
     以往的DAO是ؓ了透明不同数据库间的差异,而现在Hibernate已经做的很好。所以目前纯DAO的更大作用是Z来可以切换到别的ORMҎ比如iBatisQ但一个Pragmaic的程序员昄不会无聊Cؓ了这个机会不大的理由Q现在就d一个纯DAO层,目又不是Appfuse那样Zdemo各种ORMҎ而存在?br />
    2.2 也不使用U的薄Service?br />    在JPetStore里有一个很薄的Service层,Fascade了一堆DAOc,把这些DAOcȝ所有方法都늡的重复了一遍。而我认ؓFascade的意义在二:
    一是Controller调用Manager甲的时候,M伴随着调用Manager乙的某些Ҏ。用Fascade可以避免Controller零散的调用一堆ManagercR?br />    二是一个商业过E里可能需要同时调用DAO甲乙丙丁的方法。?br />
     q些时候,Fascade都是合理的。但我讨厌类膨胀Q所以我宁愿在甲乙丙丁中挑一个来充当Fascade的角艌Ӏ有耦合的问题吗Q对一个不是死搬书的Designer来说Q组件边界之内的cM间的耦合q不是耦合?br />
    3.去除不必要的Z接口~程
    众所周知QSpring是提倡基于接口编E的?br />    但有些Managerc,比如SaleOrderManager Q只?%的机会再有另一个Impl实现?5%旉里这两兄弟站一P像C++里的.h?cppQ徒增维护的J琐(l常要同步两个文件的函数声明)Q和代码览跌{时的不便(比如从Controlerc跟t到ServicecLQ只能蟩转到接口cȝ相应函数Q还要再按一ơ复杂的热键才蟩转到实现c?
    qMartin Flower都说Q强制每个类都分L口和实现是过犹不及。只在有多个独立实现Q或者需要消除对实现cȝ依赖Ӟ才需要分L口?br />
    3.1 DAO被强制用接口的原?/strong>
    Spring IOC本n是不会强制基于接口的Q但DAOcM般要使用Spring的声明式事务机制Q而声明式的事务机制是使用Spring AOP来实现的。Spring AOP的实现机制包括动态代理和Cgilib2Q其中Spring AOP默认使用的Java动态代理是必须Z接口Q所以就要求Z接口了?br />    
    3.2 解决Ҏ
    那就让Spring AOP改用CGLib2Q生成目标类的子cdQ我们只要指定用声明式事务的FactoryBean使用CGLib的方式来实现AOPQ就可以不基于接口编E了?br />    指定的方式ؓ讄proxyTargetClass为true。如下:

<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
id
="baseService"   abstract="true">
  
<property name="transactionManager" ref="transactionManager"/>
  
<property name="proxyTargetClass" value="true"/>

</bean>


     又因些Service Bean都是单例Q效率应该不受媄响?br />
    4.ȝ
    ҎAppfuse里面?个类Q我的Model层里只有VO作ؓU数据蝲体,ManagercL商业Ҏ。有q样太简单了Q但一个应用,要划成几个JSPQ一个ControllerQ一个ManagerQ一个VOQ对我来说已l够复杂,再要往上架墙叠屋,恕不奉陪Qv码在我的目范围里不需要?但有很多目是需要的Q神佑世人)

    后记Q迫于世人的压力Q?a href="http://www%20.springside.org.cn/">SpringSideq是把DAO和Service层分开了,但依然坚持不搞那么多接口?br />
Struts与Webwork的扇子请跌本篇?br />
    MVC不就是把M、V、C分开么?臛_物朴素的做法是两个JSP一个负责ViewQ一个负责ControllerQ再加一个负责Model的Java BeanQ已l可以工作得很好Q那时候一切都很简单?br />    而现在ؓ了一些不是本质的功能Q冒么多非标准的Web框架Q实在让Z阵郁闗像Ruby On Rails那样捷开发,可用可不用,而且没有太多的限刉要学习的Q比?strong>Webwork
q型q可以考虑。但像Struts那样用框架麻烦,或者像Tapestry那样有严重自闭們֐Q额上凿着"高手专用玩具"的,用在团队里就是不负责ȝ行ؓ了?br />

    soQ?strong>我的MVCҎ是用Spring MVC的Controller接口Q写最普通的JavaBean作ؓControllerQ本质就和当q拿JSP作Controller差不多,但拥有了Spring IOC的特性?/div>
    之所以用q么消极的选择标准Q是因ؓ觉得q一代MVC框架重回RAD时代的标准还很远Q注定了只是一D늟暂的Q过渡的技术,不值得投资太多_֊和团队学习成本?/div>

1. 原理
     Spring MVC按植物分cd属于Martin Flower〈企业应用模式〉里的静态配|型Front ControlerQ用DispatchServlet截获所?.do的请求,按照xml文g的配|,调用对应的Command对象的handleRequest(request,response)函数Q同时进行依赖对象的注入?br />     我们的Controller层,是实现handleRequest(request,response)函数的普通JavaBean?/div>

2. 优势
    
Spring MVC与struts相比的优?
     一是它的Controller有着从松到紧的类层次l构Q用户可以选择实现只有一个HandleRequest()函数的接口,也可以用它有很多回调函数的SimpleFormControllercR?/div>
     二是不需要Form BeanQ也不需要Tapestry那所谓面向对象的面对象Q对于深怕类膨胀Q改一个东西要动N个地方的人最适合不过?/div>
     三是不需要强XML配置文gQ宣告式~程是好的,但如果强制成框架Q什么都要在xml里面宣告Q写的时候繁琐,看的时候也要代码配|两边看才能明白比较麻烦了?/div>
 
     那Webwork?没有实战q,不过因ؓ对MVC框架所求就不多Q单用Spring MVC的Controller已经可以满需求,׃多搞一套Webwork来给团队讑֝Q还有给日后l护Qspring,ww2之间的版本升U添ȝ了。真有什么需要添加的QSpring MVC源代码量很少Q很Ҏ掌控和扩展?br /> 
3.化简
3.1. 直接implement ControllerQ实现handleRequest()函数
      首先Qsimple form controller非我所好,一炚w不simple。所以有时我会直接implement Controller接口。这个接口的唯一函数是供Front Controller调用的handleRequest(request,response)?br />      如果需要application对象Q比如想用application.getRealPath()Ӟpextends webApplicationObjectSupport?br />
3.2.每个Controler负责一l相关的action
       我是坚决支持一个Controler负责多个action的,一个Controler一个action像一个function一个类一h聊。所以我用最传统的方式,用URL参数如msg="insert"把一l相关action交给一个Controler控制。ROR与制作中的Groovy On Rails都是q种模式QSpring也有MultiActionController支持?br />       以上三者都是把URL参数直接反射为Controller的函敎ͼ?a >Stripes的设计可用annotation标注url action到响应函数的映射?/div>
      
3.3.xml宣告式编E的取舍 
    我的取舍很简单,反正Spring没有M强制Q我只在可能需要不重新~译而改变某些东西的时候,才把东西攑֜xml里动态注入。jsp路径之类的就l统收回到controller里面定义.
 
3.4.Data Binder
       Data Binder是Controller的必有环节,对于Spring提供的DataBinderQ照理完全可用,唯一不爽是对象如果有内嵌对象Q如订单对象里面包含了Customer对象QSpring需要你先自行创ZCustomer对象q把它赋l了Order对象Q才可能实现order.customer.customer_noq样的绑定。我hQ又拿Jakarta BeanUtils出来自己做了一个Binder?br />
3.5.提取基类
      最后还是忍不住提取了一个基c,负责MultiAction和其他一些简便的Ҏ。Sprnig的MultiActionController做得太死Q规定所有函数的W?,2个参数必Lrequest和responseQ不懂动态的Q温柔的q行参数注入?br />
      
      l过化简再化Q已l是很简单一个Java Bean QQ谁都可以L上手Q即使某q某月技术的大潮把现在所有MVC框架都没了Q也不至于没得维护?br />人生像个舞台Q请良家女d?br />    同样的,Freemarker和Velocity爱好者请跌本篇。与弃用webwork而单用Spring MVC Controller接口的理׃PFreemarker本来是一样好东西Q还跨界支持jsp 的taglibQ而且得到了WebWork的全力支持,但ؓ了它的非标准化,用户数量与IDE的缺乏,在View层我们还是用了保守但hZ用,IDE友好的JSP2.0 配合JSTL?br />
   
对于B/Sl构的企业应用Y件来_基本的页面不外两U,一U是填Form的,一U是DataGrid 数据列表理的,再配合一些css, js, ajax的效果,是View层要x的东西了?br />
1. JSP 2.0的EL代替<c:out>
JSP2.0可以直接把EL写在html部分Q而不必动?lt;c:out>节点后,老实_JSP2.0+JSTL辑ֈ的页面效果,已不比Velocity相差多少了?
<p>{goods.name}</p> 
代替
<p><c:out value="{goods.name}"/></p>

(除了EL里面不能调用goods的函敎ͼsun那帮老顽固始l坚持JSTL只能用于数据昄Q不能进行数据操作,所以不能调用bean的get/set外的Ҏ)

 2. 最懒的form 数据l定

    Spring得可怜的几个tag基本上是鸡肋Q完全可以不要?而Spring开发中的那些Simple Form tag又还没有发布。Spring的Tag主要用来把VO的值绑到input框上。但是,和Struts一P需要逐个Input框绑定,而且语法极度冗长Q遇到select框还要自p行处?....典型的Spring Sample面让h一阵头?

    ?a >jodd的form tagl了我们懒h一个懒得多的方法,只要?lt;form>两头?lt;jodd:form bean="myVO"></jodd:form>包住Q里面的所有input框,select框,checkBox...l统自动被绑定了Q这么简单的事情Q真不明白struts,springZ么不用,Z不必要的灉|性么?

<form>
<jodd:form bean="human">
<input type="text" name="name">
<input type="radiobox" name="sex" value="man">
<select name="age">
  
<option value="20">20</option>
  
<option value="30">30</option>
</select>
</jodd:form>
</form> 


不过Qjodd有个致命q是不能绑定内嵌对象的倹{比如Order(订单)对象里有个Customer(֮)对象Qjodd׃能像 struts,spring一L如下语法l定:

<input name="customer.customerNo">

q是因ؓ它的beanUtils比Jakata Common弱,用了一个错误的思\的缘故?动用beanUtils修改一下就可以了,修改后的源码可以在这里下?/font>?

3. DataGrid数据列表

DisplayTag和ValueList都属于这UŞ式的Tag Library。但最q出现的Extreme Table是真正的killerQ他本n功能强大不说Q而且从一开始就想着如何让别行扩展重载,比如Extend Attributes机制是DisplayTagq样的让千h一面者不会预留?br />

4.css, java script, ajax
天下UhQ没有什么特别想讲想推荐的,p谁吧?a >Buffalo, DWR, Scriptaculous, Prototype, AjaxTags, AjaxAnywhere, Rico, Dojo, JSON-RPCQ看着名字头痛?br />



rendong 2006-08-02 00:57 发表评论
]]>Hibernate/Spring/Struts架构使用OpenSessionInView的问题(http://forum.javaeye.com/viewtopic.php?t=15057Q?/title><link>http://www.tkk7.com/rendong/archive/2006/08/01/61202.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Tue, 01 Aug 2006 06:31:00 GMT</pubDate><guid>http://www.tkk7.com/rendong/archive/2006/08/01/61202.html</guid><wfw:comment>http://www.tkk7.com/rendong/comments/61202.html</wfw:comment><comments>http://www.tkk7.com/rendong/archive/2006/08/01/61202.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/rendong/comments/commentRss/61202.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/rendong/services/trackbacks/61202.html</trackback:ping><description><![CDATA[ <span id="o4o6a6k" class="postbody">今天有一个朋友问了我一个问题,他用的是Hibernate/Spring/Struts架构Q配|用Spring的OpenSessionInView FilterQ但是发C生效Qlazy的集合属性在面讉K的时候仍然报session已经关闭的错误。我和他一h查了所有的配置和相关的代码Q但是没有发CQ何问题。经q调试发玎ͼ应用E序使用的Session和OpenSessionInView Filter打开的Session不是同一个,所以OpenSessionInView模式没有生效Q但是ؓ什么他们不使用同一个Session呢? <br />查了一遍Spring的相x代码Q发C问题的根源: <br />通常在Web应用中初始化Spring的配|,我们会在web.xml里面配置一个ListenerQ即Q?/span>    <table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="2aiwmcw" class="genmed"><b>xml代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><span style="COLOR: #ddbb00"><</span>listener<span style="COLOR: #ddbb00">></span> <br />   <span style="COLOR: #ddbb00"><</span>listener-class<span style="COLOR: #ddbb00">><br /></span>     org.springframework.web.context.ContextLoaderListener<br /><span style="COLOR: #ddbb00">   <</span>/listener-class<span style="COLOR: #ddbb00">></span> <br /><span style="COLOR: #ddbb00"><</span>/listener<span style="COLOR: #ddbb00">></span></div></td></tr></tbody></table><span id="gesc4cc" class="postbody">如果使用StrutsQ那么需要在Struts的配|文件struts-config.xml里面配置一个Spring的pluginQContextLoaderPlugIn?<br /><br />实际上ContextLoaderListener和ContextLoaderPlugIn的功能是重叠的,他们都是q行Spring配置的初始化工作的。因此,如果你不打算使用OpenSessionInViewQ那么你q不需要在web.xml里面配置ContextLoaderListener?<br /><br />好了Q但是你现在既需要Struts集成SpringQ又需要OpenSessionInView模式Q问题就来了Q?<br /><br />׃ContextLoaderListener和ContextLoaderPlugIn功能重叠Q都是初始化SpringQ你不应该进行两ơ初始化Q所以你不应该同时用这两者,只能选择一个,因ؓ你现在需要集成StrutsQ所以你只能使用ContextLoaderPlugIn?<br /><br />但是令h困惑的是QContextLoaderListener和ContextLoaderPlugIn有一个非常矛盄地方Q?<br /><br />ContextLoaderListener初始化spring配置Q然后把它放在ServletContext对象里面保存Q?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="6yy44q4" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br />servletContext.<span style="COLOR: #000000">setAttribute</span><span style="COLOR: #000000">(</span><br />                                        WebApplicationContext.<span style="COLOR: #000000">ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE</span>, this.<span style="COLOR: #000000">context</span><span style="COLOR: #000000">)</span>;</div></td></tr></tbody></table><span id="egyg4ac" class="postbody"><br />h意,保存的对象的key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEQ?br />但是ContextLoaderPlugIn初始化spring配置Q然后把它放在ServletContext对象里面保存Q?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="6asuiqe" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><span style="COLOR: #aaaadd" ?="">String</span> attrName = getServletContextAttributeName<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />getServletContext<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">setAttribute</span><span style="COLOR: #000000">(</span>attrName, wac<span style="COLOR: #000000">)</span>;</div></td></tr></tbody></table><span id="s2qs4uk" class="postbody"><br />q个attrName和WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE名字是不一LQ?<br /><br />如果仅仅是名字不一P问题q不大,你仍然可以放心用ContextLoaderPlugInQ但是当你用OpenSessionInView的时候,OpenSessionInViewFilter是用哪个key取得spring配置的呢Q?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="2kum444" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br />WebApplicationContext wac = <br />                                WebApplicationContextUtils.<span style="COLOR: #000000">getRequiredWebApplicationContext</span><span style="COLOR: #000000">(</span>getServletContext<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">)</span>;</div></td></tr></tbody></table><span id="4aee4ay" class="postbody"><br /><br />昄QOpenSessionInViewFilter是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEq个keyLspring配置的! <br /><br />我们整理一下思\Q?<br /><br />ContextLoaderPlugIn保存spring配置的名字叫做attrNameQ?<br />QContextLoaderListener保存spring配置的名字叫做WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEQ?<br />而OpenSessionInView是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEq个名字d得spring配置的! <br />而你的应用程序却是按照attrNamed得spring的配|的Q?<br /><br />所以,OpenSessionInView模式失效Q?<br /><br />解决办法Q?<br />修改ContextLoaderPlugIn代码Q在getServletContext().setAttribute(attrName, wac);q个地方加上一行代码: <br />getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); <br /><br />或者修改OpenSessionInViewFilterQ让它按照attrNamed得spring配置?br /><br /><br /><br /><span id="gqk46ee" class="postbody">我原来用struts/spring/hibernate的时候同样用OpenSessionInViewQ但是似乎没有robbin所说的问题啊。而且我在使用的时候,是ContextLoaderListener和ContextLoaderPlugIn一L的。整个配|如下: <br />1.首先是web.xml <br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="2ww4ca4" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br />        <filter> <br />        <filter-name>OpenSessionInViewFilter</filter-name> <br />        <filter-<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>>org.<span style="COLOR: #000000">springframework</span>.<span style="COLOR: #000000">orm</span>.<span style="COLOR: #000000">hibernate</span>.<span style="COLOR: #000000">support</span>.<span style="COLOR: #000000">OpenSessionInViewFilter</span></filter-<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>> <br />    </filter> <br />    <br />    <filter-mapping> <br />        <filter-name>OpenSessionInViewFilter</filter-name> <br />        <url-pattern><span style="COLOR: #6666ff">/*</url-pattern> <br />    </filter-mapping> <br />    <br />    <listener> <br />                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <br />        </listener> <br /><br />...... <br /></span></div><br /></td></tr></tbody></table><span id="2u444m4" class="postbody"><br /><br />2. 然后是struts-config.xmlQ?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="6suw4g4" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><plug-in className="org.<span style="COLOR: #000000">springframework</span>.<span style="COLOR: #000000">web</span>.<span style="COLOR: #000000">struts</span>.<span style="COLOR: #000000">ContextLoaderPlugIn</span>"> <br />        <set-property property="contextConfigLocation" <br />                                  value="/WEB-INF/action-servlet.<span style="COLOR: #000000">xml</span>" <br />        /> <br /></plug-in> <br /></div><br /></td></tr></tbody></table><span id="g4ce6gm" class="postbody"><br /><br />其余部分省略?<br /><br />在上q配|下Q用OpenSessionInViewg没有问题?<br /><br />不知道robbin所说的ContextLoaderListener和ContextLoaderPlugIn不应该同时用是不是做得是如下的配置Q(struts-config.xmlQ?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="2iaesqa" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><plug-in <br />className="org.<span style="COLOR: #000000">springframework</span>.<span style="COLOR: #000000">web</span>.<span style="COLOR: #000000">struts</span>.<span style="COLOR: #000000">ContextLoaderPlugIn</span>"> <br /><set-property property="contextConfigLocation" <br />value="/WEB-INF/applicationContext.<span style="COLOR: #000000">xml</span>, <br />/WEB-INF/action-servlet.<span style="COLOR: #000000">xml</span>"/> <br /></plug-in> <br /></div><br /></td></tr></tbody></table><span id="mc2a4q4" class="postbody"><br /><br />我尝试了一下,用这U配|时QOpenSessionInView的确失效了?<br /><br />我猜惻I原因大概是这Pstruts的这个plugInQ可能只是ؓ了整合一个action-servlet.xmlQ将action-servlet.xml中的定义当作Spring的bean来用,因此Q在保存Ӟ只要有action-servlet.xml的配|,p保存到robbin所提到的那个attrName中,而不是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE中,所以,OpenSessionInView是取不到q个配置的?<br /><br />那么q个配置什么时候被取到呢?直觉告诉我,可能是和Action的Proxy有关。于是,查看了org.springframework.web.struts.DelegatingActionProxy的源码,果然Q?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="yoo2eiy" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><span style="COLOR: #6666ff">/** <br />        * Return the delegate Action for the given mapping. <br />        * <p>The default implementation determines a bean name from the <br />        * given ActionMapping and looks up the corresponding bean in the <br />        * WebApplicationContext. <br />        * @param mapping the Struts ActionMapping <br />        * @return the delegate Action <br />        * @throws BeansException if thrown by WebApplicationContext methods <br />        * @see #determineActionBeanName <br />        */</span><br />        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">protected</span><span style="COLOR: #aaaadd" ?="">Action</span> getDelegateAction<span style="COLOR: #000000">(</span>ActionMapping mapping<span style="COLOR: #000000">)</span><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">throws</span> BeansException <span style="COLOR: #000000">{</span><br />                WebApplicationContext wac = getWebApplicationContext<span style="COLOR: #000000">(</span>getServlet<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>, mapping.<span style="COLOR: #000000">getModuleConfig</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">)</span>; <br />                <span style="COLOR: #aaaadd" ?="">String</span> beanName = determineActionBeanName<span style="COLOR: #000000">(</span>mapping<span style="COLOR: #000000">)</span>; <br />                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">return</span><span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">Action</span><span style="COLOR: #000000">)</span> wac.<span style="COLOR: #000000">getBean</span><span style="COLOR: #000000">(</span>beanName, <span style="COLOR: #aaaadd" ?="">Action</span>.<span style="COLOR: #000000">class</span><span style="COLOR: #000000">)</span>; <br />        <span style="COLOR: #000000">}</span><br /><br />        <span style="COLOR: #6666ff">/** <br />        * Fetch ContextLoaderPlugIn's WebApplicationContext from the <br />        * ServletContext, containing the Struts Action beans to delegate to. <br />        * @param actionServlet the associated ActionServlet <br />        * @param moduleConfig the associated ModuleConfig <br />        * @return the WebApplicationContext <br />        * @throws IllegalStateException if no WebApplicationContext could be found <br />        * @see DelegatingActionUtils#getRequiredWebApplicationContext <br />        * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX <br />        */</span><br />        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">protected</span> WebApplicationContext getWebApplicationContext<span style="COLOR: #000000">(</span><br />                        ActionServlet actionServlet, ModuleConfig moduleConfig<span style="COLOR: #000000">)</span><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">throws</span><span style="COLOR: #aaaadd" ?="">IllegalStateException</span><span style="COLOR: #000000">{</span><br />                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">return</span> DelegatingActionUtils.<span style="COLOR: #000000">getRequiredWebApplicationContext</span><span style="COLOR: #000000">(</span>actionServlet, moduleConfig<span style="COLOR: #000000">)</span>; <br />        <span style="COLOR: #000000">}</span><br /></div><br /></td></tr></tbody></table><span id="ik246oe" class="postbody"><br /><br />仔细看其中的取wac的代码,它ƈ不是从WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE取的wac?<br /><br />由此Q我怿Q除了robbin讲的修改源码以外Q同时用ContextLoaderListener和ContextLoaderPlugInQ但是不要在ContextLoaderPlugIn里面加入applicationContext.xmlQ只要加入你的action-servlet.xmlQ我怿Q同样也可以非常畅的用OpenSessionInView</span> ?br /><br /><br /><span id="4ugy2qy" class="postbody">我也遇到了上面说的openSessionInView不v作用的问题(web.xml既定义了listenerQ也定义了struts pluginQ,我想问一下,上面提到的action-servlet.xml到底是什么内容? <br />在我的应用里spring的配|文件是application-context.xmlQ它本n是空的,引用spring-data.xmlQsping-security.xml{等和存攑֯应struts action的spring 配置文gspring-struts-action.xml?<br />struts的配|文件是struts-config.xmlQ里面定义了所有的actionQ它们的class都是org.springframework.web.struts.DelegatingActionProxy。最后的plug-in?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="kmaa44o" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><plug-in <br />className="org.<span style="COLOR: #000000">springframework</span>.<span style="COLOR: #000000">web</span>.<span style="COLOR: #000000">struts</span>.<span style="COLOR: #000000">ContextLoaderPlugIn</span>"> <br /><set-property property="contextConfigLocation" <br />value="/WEB-INF/applicationContext.<span style="COLOR: #000000">xml</span>"/> <br /></plug-in> <br /></div><br /></td></tr></tbody></table><span id="4i2k242" class="postbody"><br /><br />l果也遇CopenSessionInView不v作用的问?<br />在我的应用里都没有出现过action-servlet.xmlQ我想问下它到底是什么?是对应于我的spring-struts-action.xmlq是struts-config.xml引用的一部分Q?<br /><br />通俗的说Q这个action-servlet.xml到底是spring配置文gq是struts的配|文Ӟ</span><br /><br /><br /><br /><br /><br /><br /><span id="u44iweu" class="postbody">我仔l想了一下,那个action-servlet.xml应该是spring配置的一部分Q也是说对应我的spring-struts-action.xmlQ明的_q个里面的xml语法是spring配置文g的)Q应该是q样的吧Q不q按照这个理解下去,我又产生了问题?<br />我的理解时这LQspring里面的listener会在web.xml里加载spring的容器,struts ActionServlet初始化时又会Ҏstruts-config.xml里的spring plugin配置再初始化一个spring容器Q所以原则上说只要一个就可以了,如果2处都配了Q会初始?个spring容器Q在和strutsl合的用法里Q实际有效的是stuts配置里面那个plugin初始化的容器Q因为用h作的入口都是struts的action。那么二楼提供的Ҏ其实是所有的bean都由那个listener初始化的Q存在于W一个spring容器中,然后stuts只初始化那些和struts action兌的action beanQ存在第二个容器里(q两个容器的区分在于robbin提到的他们的名字不同Q但是问题就是: <br />Z么在二楼的的Ҏ中,用户通过action讉Kspring beanQ那么应该只是访问的W二个容器里的action beanQ而service bean在第一个容器里Q那W二个容器里的action bean是怎么会可以访问到W一个容器里的service bean和其他所有spring bean的呢Q实在是费解</span> ?br /><br /><br /><br /><br /><br /><br /><br /><span id="au44sye" class="postbody">感谢搂主的分析,spring的struts plugin实有上q描q的问题 <br />如果Ҏ原来的方法,context会初始化2ơ,看了plugin的源码以后我对它作了小的修改,首先查context是不是被初始化过Q如果有则直接从attribute中获取,如果没有初始化,则根据plugin的配|初始化Q同时保证了context只被初始化一ơ?<br />原来的意图是屏蔽web.xml中的context监听Q直接用plugin初始化contextQ但启动p|Q于是作了上qC?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="woc4iem" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><span style="COLOR: #6666ff">//read the application context from the aplication attribute</span><br />                WebApplicationContext wac = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />                <span style="COLOR: #aaaadd" ?="">String</span> attrName = getServletContextAttributeName<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>getServletContext<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">getAttribute</span><span style="COLOR: #000000">(</span>WebApplicationContext.<span style="COLOR: #000000">ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE</span><span style="COLOR: #000000">)</span>!=<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span>                        <br />                        wac = <span style="COLOR: #000000">(</span>WebApplicationContext<span style="COLOR: #000000">)</span> getServletContext<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">getAttribute</span><span style="COLOR: #000000">(</span>WebApplicationContext.<span style="COLOR: #000000">ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE</span><span style="COLOR: #000000">)</span>; <br />                        logger.<span style="COLOR: #000000">info</span><span style="COLOR: #000000">(</span>"Using the context listener<span style="COLOR: #0000ff">'s context "+wac); <br />                } <br />                else { <br />                        logger.info("Load the context plugin application context "); <br />                        WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); <br /><br />                        wac = createWebApplicationContext(parent); <br />                        if (logger.isInfoEnabled()) { <br />                                logger.info("Using context class '</span>" + wac.<span style="COLOR: #000000">getClass</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">getName</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span> + "<span style="COLOR: #0000ff">' for servlet '</span>" + getServletName<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span> + "<span style="COLOR: #0000ff">'"); <br />                        }                        <br />                        //set to attribute to spring listener <br />                        getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);                 <br />                } <br />                <br />                // Publish the context as a servlet context attribute. <br />                getServletContext().setAttribute(attrName, wac); <br /></span></div><br /></td></tr></tbody></table></span><span id="g2a4uq4" class="postbody"><br /><br />PS. 有个疑问Q如果说spirng中的bean只有一个实例,应该说无论初始化多少ơ都应该获得的是同一个实例啊Q?/span><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><br /><br /><div align="center"><hr width="95%" /></div><table class="attachtable" cellspacing="0" cellpadding="2" width="95%" align="center" border="1"><tbody><tr><td class="attachheader" align="middle" width="100%" colspan="3"><b><span id="4iuea4c" class="gen">strutspugin.rar</span></b></td></tr><tr><td class="attachrow" width="15%"><span id="a2g44kg" class="genmed"> 描述:</span></td><td class="attachrow" width="75%"><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span id="ik2cq44" class="genmed">Ҏspirng 1.2.7 重新~译的ContextLoaderPlugin</span></td></tr></tbody></table></td><td class="attachrow" align="middle" width="10%" rowspan="4"><img alt="" src="http://forum.javaeye.com/images/icon_clip.gif" border="0" /><br /><a class="genmed" ><b><font color="#002c99">下蝲</font></b></a></td></tr><tr><td class="attachrow" width="15%"><span id="iu44iww" class="genmed"> 文g?</span></td><td class="attachrow" width="75%"><span id="ac22444" class="genmed"> strutspugin.rar</span></td></tr><tr><td class="attachrow" width="15%"><span id="uu46i44" class="genmed"> 文g大小:</span></td><td class="attachrow" width="75%"><span id="2qsea4s" class="genmed"> 4.16 KB</span></td></tr><tr><td class="attachrow" width="15%"><span id="w2c4cus" class="genmed"> 下蝲q的:</span></td><td class="attachrow" width="75%"><span id="gyogwwm" class="genmed"> 文g被下载或查看 194 ?/span></td></tr></tbody></table><div align="center"><hr width="95%" /></div><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><br /><br /><br /><br /><br /><span id="u4ciwem" class="postbody">我觉得这个根本就是大家对Spring的理解的问题?<br /><br />如果q真是一个严重的问题Q以至于需要修Ҏ码来修正QSpring的team不会到现在没有发玎ͼ到现在还没有修正。ؓ什么Spring的context分成了多个文ӞZ么用applicationContext.xml了,q有xxx-servlet.xmlQ?<br /><br /><br />如果大家监听ContextRefreshedEvent的话Q会发现一个web app臛_会有两个q样的eventQ下面是我的现在的应用打印出的context及其所包含的beansQ?<br /><span style="COLOR: darkblue">org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date <br />[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST <br />2006]; root of context hierarchy]; config locations <br />[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath <br />*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context- <br />ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml] <br /></span><br /><span style="COLOR: blue">[messageSource, localeResolver, exposeSpringBeanDefinition, dataListOfTerminalInfoForm, dataListOfPointsSpecialOfferForm, <br />dataListOfSearchTerminalForm, pointsSpecialOfferForm1, terminalInfoForm1, searchTerminalForm1, <br />dataListOfSearchCardAccountDetailForm, dataListOfSearchPhysicalCardInfoForm, dataListOfSearchCardApplicationInfoForm, <br />dataListOfSearchTransactionForm, searchCardAccountDetailForm1, searchCardAccountDetailForm2, searchCardAccountDetailForm3, <br />searchPhysicalCardInfoForm1, searchPhysicalCardInfoForm2, searchPhysicalCardInfoForm3, searchTransactionForm1, searchTransactionForm2, searchTransactionForm3, displayTransactionFormForTest, dataListOfReplaceCardForm, dataListOfSearchCardInfoForm, cardInfoFormForTest, cardAccountForm1, cardAccountForm2, cardAccountForm3, searchCardInfoForm1, searchCardInfoForm2, searchCardInfoForm3, replaceCardForm1, replaceCardForm2, replaceCardForm3, <br />searchCardApplicationInfoForm1, searchCardApplicationInfoForm2, searchCardApplicationInfoForm3, <br />displayCardApplicationInfoFormForTest, displayCardApplicationInfoFormForTest1, csvDisplayProvider, excelDisplayProvider, <br />classicLook, simpleLook, microsoftLook, dacHandler, integer0, integer1, integer2, integer3, integer4, integer5, integer6, integer7, integer8, integer9, sessionFactory, transactionManager, hibernateTemplate, abstractHibernateDao, abstractDacHolderHibernateDao, ageLevelDefinitionDao, auditLogDao, bankDao, bankBranchDao, binRangeDao, cardDao, <br />cardAccountDao, cardAccountDetailDao, cardApplicationDao, cardSalesAgentDao, cardTypeDefinitionDao, centerDao, <br />centerAccountDao, centerAccountDetailDao, corporationDao, corporationTypeDefinitionDao, csaAccountDao, csaAccountDetailDao, csaBillsDao, csaTypeDefinitionDao, educationLevelDefinitionDao, generalLedgerDao, generalLedgerDetailDao, generalLedgerTypeDefinitionDao, identificationTypeDefinitionDao, incomeLevelDefinitionDao, industryDao, journalDao, journalBackupDao, maritalStatusDefinitionDao, merchantDao, merchantAccountDao, merchantAccountDetailDao, merchantApplicationDao, merchantBillsDao, merchantTypeDefinitionDao, occupationTypeDefinitionDao, outboundEmailDao, permissionDao, physicalCardDao, pointsSpecialOfferDao, residentialTypeDefinitionDao, roleDefinitionDao, rolePermissionDao, <br />systemConfigDao, terminalDao, terminalConfigurationDao, terminalModelDefinitionDao, transactionSummaryDao, <br />transactionTypeDefinitionDao, userDao, userCreditRatingDao, userLevelDefinitionDao, userRoleDao, sqlMapClient, <br />abstractIbatisValueListAdapter, valueListHandler, propertyConfigurer, dataSource, voidTransactionTemplate, <br />inquiryBalanceTransactionTemplate, definitionBizFacade, facadeHolder, pointsTransactionTemplate, emailBizObject, <br />clsSpringEventListener, balanceBizFacadeTarget, kernelBizObject, printBizFacadeTarget, pointsSpecialOfferBizFacadeTarget, <br />settlementBizObject, addPointsTransactionTemplate, inquiryMerchantAccountInfoTransactionTemplate, <br />addMerchantPointsTransactionTemplate, emailBizFacadeTarget, centerBizFacadeTarget, monitorBizFacadeTarget, <br />endOfDayReportTransactionTemplate, cardBizFacadeTarget, pointsCalculator, balanceBizObject, pointsSpecialOfferBizObject, <br />auditLogBizFacadeTarget, terminalBizFacadeTarget, terminalBizObject, templateHolder, settlementBizFacadeTarget, <br />merchantBizObject, userBizObject, changePinTransactionTemplate, centerPurchasePointsBackTransactionTemplate, <br />definitionBizObject, monitorBizObject, auditLogBizObject, merchantBizFacadeTarget, userBizFacadeTarget, <br />responseMessageDataFactoryBean, tradingBizObject, printBizObject, csaBizObject, csaBizFacadeTarget, kernelBizFacadeTarget, <br />cardBizObject, centerBizObject, tradingBizFacadeTarget, downloadParametersTransactionTemplate, baseTransactionProxy, <br />abstractDataFacade, balanceBizFacade, printBizFacade, settlementBizFacade, emailBizFacade, kernelBizFacade, <br />auditLogBizFacade, pointsSpecialOfferBizFacade, terminalBizFacade, userBizFacade, merchantBizFacade, csaBizFacade, <br />monitorBizFacade, cardBizFacade, centerBizFacade, tradingBizFacade, pointsConverter, transactionTypeHelperBean, integer100, integer106, integer110, integer111, integer120, integer180, integer181, integer182, integer200, integer220, integer221]</span><br /><br /><span style="COLOR: darkblue"><br />---------------------------------------------------------------context2 <br />org.springframework.web.context.support.XmlWebApplicationContext: display name [WebApplicationContext for namespace <br />'action-servlet']; startup date [Wed May 10 17:31:01 CST 2006]; child of <br />[org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date <br />[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name <br />[org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST <br />2006]; root of context hierarchy]; config locations <br />[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath <br />*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context- <br />ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml]]; config <br />locations [/WEB-INF/action-servlet.xml] <br /></span><br /><span style="COLOR: blue">[/EditCurrentUserInfoAction, /FakeLoginAction, /SaveCardInfoAction, /LoginAction, /EditOperatorPswAction, <br />/SavePointsSpecialOfferAction, /DisplayCurrentUserInfoAction, /DisplayOperatorApplicationAction, /EditEmailAction, <br />/RegisterCardAction, /IssueCardsAction, /SearchEmailAction, /RegisterCsaAction, /EditTerminalInfoAction, <br />/ReleaseTerminalAction, /ReleaseCsaAction, /SaveTerminalInfoAction, /SearchTransactionAction, /SearchOperatorInfoAction, <br />/ProcessCardApplicationAction, /EditTerminalConfigurationAction, /EditGenericUserByIdAction, /SearchMerchantInfoAction, <br />/SearchTerminalAction, /SaveCsaPswAction, /SaveCsaInfoAction, /SaveCardTypeAction, /RegisterPointsSpecialOfferAction, <br />/SearchCardInfoAction, /EditMerchantInfoAction, /SearchCardAccountDetailAction, /SearchCardApplicationInfoAction, <br />/DisplayTransactionStatisticsAction, /DisplayRegisterCardInfoAction, /SaveEmailAction, /EditCardInfoByIdAction, <br />/MoniterSystemLogAction, /ReleasePointsSpecialOfferAction, /SearchMerchantAccountDetailAction, /EditMerchantPswAction, <br />/ReleaseMerchantAction, /ListCardTypeAction, /StockCardsAction, /ProcessOperatorApplicationAction, <br />/SearchPhysicalCardInfoAction, /SearchCsaInfoAction, /SearchOperatorApplicationAction, /ReleaseOperatorAction, <br />/DisplayCardApplicationInfoAction, searchEmailValueListBuilder, /SearchCsaApplicationAction, /RegisterCardTypeAction, <br />/MonitorTerminalStatusAction, /SearchCsaAccountDetailAction, /SearchUserAction, /ReleaseCardTypeAction, /ReleaseUserAction, <br />/ReleaseEmailAction, /CreateBlankCardsAction, /RegisterBulkCardsAction, /SaveMerchantPswAction, <br />/SearchPointsSpecialOfferAction, /EditPswAction, /SearchMerchantApplicationAction, /DisplayCsaApplicationAction, <br />/EndOfDayAction, /EditPointsSpecialOfferAction, /DisplayMerchantApplicationAction, /RegisterEmailAction, /EditCsaPswAction, <br />/ProcessMerchantApplicationAction, /EditCardTypeDefinitionAction, /SaveOperatorInfoAction, /SaveMerchantInfoAction, <br />/SaveOperatorPswAction, /EditOperatorInfoAction, /RegisterMerchantAction, /EditCsaInfoAction, /ChangeSystemStatusAction, <br />/ProcessSystemLogAction, /RegisterOperatorAction, /RegisterTerminalAction, /DisplayTransanctionAction, <br />/ProcessCsaApplicationAction, /MerchantPointsRedeemTransactionReportAction, /SaveTerminalConfigurationAction, <br />autoProxyCreator, profilingAdvice, profilingAdvisor, strutsActionAdvice, baseSearchAction, userTypeBasedSelector, <br />valueListBuilder]</span><br /><br /><span style="COLOR: darkblue"><br />------------------------------------------------------------------------context3 <br />org.springframework.web.context.support.XmlWebApplicationContext: display name [WebApplicationContext for namespace <br />'trading-servlet']; startup date [Wed May 10 17:31:08 CST 2006]; child of <br />[org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date <br />[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name <br />[org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST <br />2006]; root of context hierarchy]; config locations <br />[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath <br />*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context- <br />ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml]]; config locations [/WEB-INF/trading-servlet.xml] <br /></span><span style="COLOR: blue">[clsRawTagElementParser, transactionProcessor, clsTradingServlet, rawTagElementParser]</span><br /><br /><br /><br />如果照大家所说的ҎL源代码,那么后启动的servlet的context会覆盖前面一个启动的servlet的contextQ对于我的应用来_那种方式会导致action-servlet丢失。开始robbin提出的错误,是因Z在strutsPlugin里多配置了appContextQ导致实际上?分appContext的beans存在Qchild在自qcontext里就可以扑ֈ所需要的beanQ也׃会去parent里找了。StrutsPlugin里的attrName是正合理的?<br /><br />当然你可以把所有所有的bean全部攑ֈroot context里,q也行的通,不过本h极力反对q种方式Qbean的组l太乱?<br /><br />Spring的context是分层次的:不要把在写contextConfigLocation的时候,把你的xxx-servlet.xml路径也加q去Q不要在写xxx-servlet.xml的context的时候把applicationContext的\径也配进去;不要在parent的context里引用children里的beanQ不要在你的appContext里引用xxx-servlet的bean?<br /><br />MQ就是要求你合理的、有层次的组l你的benaQ而不是一陀摆出来?/span><br /><br /><br /><br /><br /><span id="i44yi4q" class="postbody">applicationContext.xml如果不引用action-servlet.xml路径的话Q那么action如何来引用boQ?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="is4y2ua" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><bean name="/test" <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="com.<span style="COLOR: #000000">xy</span>.<span style="COLOR: #000000">action</span>.<span style="COLOR: #000000">TestAction</span>"> <br />  <property name="testBo"><ref bean="testBoProxy"/></property> <br /></bean> <br /></div><br /></td></tr></tbody></table><span id="qge4som" class="postbody"><br /><br />如果bo在applicationContext.xml中的? <br />服务器会报错,找不到bo</span> ?br /><br /><br /><br /><br /><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="wg22syy" class="genmed"><b>okokok 写道:</b></span></td></tr><tr><td class="quote">applicationContext.xml如果不引用action-servlet.xml路径的话Q那么action如何来引用boQ?<br /><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="4y42o2y" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><bean name="/test" <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="com.<span style="COLOR: #000000">xy</span>.<span style="COLOR: #000000">action</span>.<span style="COLOR: #000000">TestAction</span>"> <br />  <property name="testBo"><ref bean="testBoProxy"/></property> <br /></bean> <br /></div><br /></td></tr></tbody></table><span id="uui4kyw" class="postbody"><br /><br />如果bo在applicationContext.xml中的? <br />服务器会报错,找不到bo</span></td></tr></tbody></table><span id="i444e4w" class="postbody"><br /><br />我不太清楚你的bean的组l,在我的系l里QBO是在applicationContext之类的基context里定义,而且工作很正常?<br /><br />另外你需要搞清楚的是Q对于Spring的BeanFactoryQApplicationContextQ,如果它在自己的context里找不到beanQ会去parent里找?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="ik4ce44" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><span style="COLOR: #6666ff">// Check if bean definition exists in this factory.</span><br />                        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>getParentBeanFactory<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span> != <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span> && !containsBeanDefinition<span style="COLOR: #000000">(</span>beanName<span style="COLOR: #000000">)</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />                                <span style="COLOR: #6666ff">// Not found -> check parent.</span><br />                                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>getParentBeanFactory<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span> instanceof AbstractBeanFactory<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />                                        <span style="COLOR: #6666ff">// Delegation to parent with args only possible for AbstractBeanFactory.</span><br />                                        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">return</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">(</span>AbstractBeanFactory<span style="COLOR: #000000">)</span> getParentBeanFactory<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">getBean</span><span style="COLOR: #000000">(</span>name, requiredType, args<span style="COLOR: #000000">)</span>; <br />                                <span style="COLOR: #000000">}</span><br />                                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">else</span><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>args == <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />                                        <span style="COLOR: #6666ff">// No args -> delegate to standard getBean method.</span><br />                                        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">return</span> getParentBeanFactory<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>.<span style="COLOR: #000000">getBean</span><span style="COLOR: #000000">(</span>name, requiredType<span style="COLOR: #000000">)</span>; <br />                                <span style="COLOR: #000000">}</span><br />                                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">else</span><span style="COLOR: #000000">{</span><br />                                        throw <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">new</span> NoSuchBeanDefinitionException<span style="COLOR: #000000">(</span>beanName, <br />                                                        "Cannot delegate to parent BeanFactory because it does not supported passed-in arguments"<span style="COLOR: #000000">)</span>; <br />                                <span style="COLOR: #000000">}</span><br />                        <span style="COLOR: #000000">}</span><br /></div><br /></td></tr></tbody></table><span id="2kmo4w4" class="postbody"><br /><br />所以无论如何,只要你在applicationContext里定义了BOQ那么webApp的context一定找得到q个beanQ因为applicationContext是webApp的context的parent?/span><br /><br /><br /><br /><br /><br /><span id="aiequ4q" class="postbody">奇了怪了Q昨天一直报找不到bo的错Q今天居然没报错Q服务器有问题? <br />q有个问题,既然web.xml里可以用listener来加载applicationContext.xmlQؓ什么还要在struts-config.xml里再用plug-inQ我觉得在applicationContext.xml里按模块攄每个模块的action,bo,dao的xml文g的\径是个不错方法,比如Q?<br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="ga22esq" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br /><?xml version="<span style="COLOR: #000000" ?="">1</span>.<span style="COLOR: #000000" ?="">0</span>" encoding="UTF-<span style="COLOR: #000000" ?="">8</span>"?> <br /><!DOCTYPE beans <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">PUBLIC</span> "-<span style="COLOR: #6666ff">//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"></span><br /><beans> <br />        <<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">import</span> resource="SpringConfig/module1.<span style="COLOR: #000000">xml</span>" /> <br />                <<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">import</span> resource="SpringConfig/module2.<span style="COLOR: #000000">xml</span>" /> <br />                <<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">import</span> resource="SpringConfig/module3.<span style="COLOR: #000000">xml</span>" /> <br /><br />        <bean id="dataSource" <br />                <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="org.<span style="COLOR: #000000">apache</span>.<span style="COLOR: #000000">commons</span>.<span style="COLOR: #000000">dbcp</span>.<span style="COLOR: #000000">BasicDataSource</span>"> <br />                <property name="driverClassName"> <br />                        <value>org.<span style="COLOR: #000000">gjt</span>.<span style="COLOR: #000000">mm</span>.<span style="COLOR: #000000">mysql</span>.<span style="COLOR: #000000">Driver</span></value> <br />                </property> <br />                <property name="url"> <br />                        <value>jdbc:mysql:<span style="COLOR: #6666ff">//localhost/airline</value></span><br />                </property> <br />                <property name="username"> <br />                        <value>root</value> <br />                </property> <br />                <property name="password"> <br />                        <value><span style="COLOR: #000000" ?="">123456</span></value> <br />                </property> <br />        </bean> <br />         ... <br /></beans> <br /></div><br /></td></tr></tbody></table><span id="mws4w4c" class="postbody"><br />而module1.xml的内ҎQ?<br /><br /></span><table cellspacing="1" cellpadding="3" width="90%" align="center" border="0"><tbody><tr><td><span id="eoce44g" class="genmed"><b>java代码: </b></span></td></tr><tr><td class="code"><div style="FONT-FAMILY: 'Courier New', Courier, monospace"><br /><br />?lt;?xml version="<span style="COLOR: #000000" ?="">1</span>.<span style="COLOR: #000000" ?="">0</span>" encoding="UTF-<span style="COLOR: #000000" ?="">8</span>"?> <br /><!DOCTYPE beans <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">PUBLIC</span> "-<span style="COLOR: #6666ff">//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"></span><br /><beans> <br /><!-- 数据讉K?--> <br /><bean id="testDao" <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="com.<span style="COLOR: #000000">xy</span>.<span style="COLOR: #000000">dao</span>.<span style="COLOR: #000000">TestDao</span>"> <br />  <property name="sessionFactory"><ref bean="sessionFactory"/></property> <br /></bean> <br /><!-- 业务|基?--> <br /><bean id="testBo" <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="com.<span style="COLOR: #000000">xy</span>.<span style="COLOR: #000000">bo</span>.<span style="COLOR: #000000">TestBo</span>"> <br />  <property name="testDao"><ref bean="testDao"/></property> <br />  <!-- <property name="transactionManager"><ref bean="transactionManager"/></property> --> <br /></bean> <br /><!-- <span style="COLOR: #aaaadd" ?="">Action</span>?--> <br /><bean name="/test" <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span>="com.<span style="COLOR: #000000">xy</span>.<span style="COLOR: #000000">action</span>.<span style="COLOR: #000000">TestAction</span>"> <br />  <property name="testBo"><ref bean="testBoProxy"/></property> <br /></bean> <br /></beans> <br /></div><br /></td></tr></tbody></table><span id="ik2cw4i" class="postbody"><br />q样的话不用在struts-config.xml里配|plug-in了吧</span> ?br /><br /><br /><br /><br /><span id="ey4yq44" class="postbody">struts-config.xml里配|plug-in是要配的Q关键在于你Spring的配|文件的合理分层Q如果像你那样什么东襉K攑֜一个applictionContext里,那么有可能出现象这样OpenSessioInView失效的这样“意想不到”的问题。而且会导致你错误地理解SpringQ比如Spring的ApplicationEventQ本wweb层的context里的Listener是听不到root层的Event的,但是你这L配置Q也是这个topic的配|)会导致EventhQ也q背了Spring本n的设计意图?<br /><br />PS:关于Event的问题可以看我blogQhttp://spaces.msn.com/sweetriver/blog/cns!367370EB9A9B2807!129.entry <br /><br />在我的配|里Q各个层ơ都有属于自q配置文gQmessageSource同样应该有分层,Z图方便而简单吧所有bean|列在一个配|里是不可取的,而且会导致某些设计与实现上的问题Q开始我的messageSource是没有分层的Q但是后来这样导致了一些非常痛苦的问题与抉择,l果q是改回分层的messageSourceQ?/span><br /><br /><br /><br /><br /><span id="c2iy4i4" class="postbody">applicationContext是有层次的,那样的方式会让struts plugIn中配|的sessionFactory比root中的sessionFactory占优Q这个struts plugIn中的bean都是讉Kq里配置的sessionFactory?/span><br /><br /><br /><br /><span id="4ss4eky" class="postbody">opensession的最大问题还是长链接的时候无法释放session的问题,在对外系l中问题ؓH出。springMVC可以仗着先天优势用interecptorQ但是webwork可就没有q样的优势了Q尝试自己做一个适合webwork的,但是发现一旦有安全框架介入Qsession作用的切面就变得难以把握。到现在q无果~~~~</span><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><span id="wwc4wki" class="postbody"></span><span id="4k4u44c" class="gensmall"></span><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><br /><style type="text/css"><!-- td.attachrow { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; } td.attachheader { font: normal 11px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; background-color: #D1D7DC; } table.attachtable { font: normal 12px Verdana, Arial, Helvetica, sans-serif; color : #000000; border-color : #000000; border-collapse : collapse; } --></style><img src ="http://www.tkk7.com/rendong/aggbug/61202.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/rendong/" target="_blank">rendong</a> 2006-08-01 14:31 <a href="http://www.tkk7.com/rendong/archive/2006/08/01/61202.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring让Hibernate使用者受益良多[转蝲]http://www.tkk7.com/rendong/archive/2006/08/01/61188.htmlrendongrendongTue, 01 Aug 2006 05:54:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/01/61188.htmlhttp://www.tkk7.com/rendong/comments/61188.htmlhttp://www.tkk7.com/rendong/archive/2006/08/01/61188.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61188.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61188.htmlSpring的轻量的bean容器Z务对象(business objectsQ、DAO对象和资源(如:JDBC数据源或者Hibernate SessionFactorie{)对象提供了IoCcd的装配能力。Spring使用一个xml格式的应用配|文件ؓ开发者提供了一U通过解析定制的属性文件来手动理单实例对象或者工厂对象的选择性。由于Spring非入R性做Z个重要的目标Q因此可以由Spring配置理的bean对象均不需要依赖Spring自有的接口和cd可以通过它们的bean属性完成配|。这个概念可以被应用CQ何环境中Q无Z开发的是一个J2EE的web应用q是一个桌面应用甚臛_是一个applet都可以?

    在用Hibernate的应用中, Spring的对DAO对象通常的事务管理特别应该引起关注。它的目的就是分L据访问和事务处理Q事务性业务对象不与Q何特D的数据讉K或者事务策略绑在一P从而不影响业务对象的可复用性。这U划分既可以l由事务模板QTransactionTemplateQ用~程的方式实玎ͼ也可以经由面向方面(AOPQ事务拦截器QTransactionTemplateQ用声明的方式实现。无论是本地的Hibernate / JDBC事务Q还是JTA事务都支持对象外的事务策略,q对于本地的无状态会话BeanQStateless Session BeansQ是一个非常有用的选择?/font>

    Spring的HibernateTemplatecL供了一个简单的方式实现了Hibernate-based DAO对象而不必关心如何获得Hibernate的Session实例Q也不必兛_多方参与的事务处理。无需使用try-catch块,也无需q行事务查。一个简单的Hibernate讉KҎ完全解决了些麻? 无论是在多个DAO接口q是在多方事务的情况下,Spring使得多种DAO对象无缝地协同工作。例如:某些DAO对象可能是基于plain JDBC的实玎ͼ更适合于经由Spring的JdbcTemplate来避免手动的异常处理?/font>

      你可以单独地使用许多SpringҎ,因ؓSpring的所有对象都是设计成可复用的JavaBean对象的集合。也不要因ؓSpring可以提供一个完整的应该框架而气馁!使用其他的SpringҎ时Q应用配|概忉|一个附加的Ҏ,q不是一个必ȝҎ。无论如何,当你要决定去构徏一个象Springq样的内在的基础架构的时候,在用Spring的\途上没有什么范围上的限制?/font>

1. 介绍: 资源理

       典型的业务应用系l常常由于重复的资源理代码而导致؜乱。许多项目试着用自qҎ来解册个问题,有时要ؓ此付出失败的代hQSpring针对适当的资源管理提倡了一U引人注目的单方法:即经由模板来倒置控制QInversion of controlQ,例如Q基cM用回调接口,或者应用AOP拦截器。其基础核心是适当的资源处理和特D的API异常转换Z个unchecked的基异常?/font>

       Spring引入了一个DAO异常层适用于Q何数据访问策略。对于直接的JDBCQJdbcTemplatecd注于q接处理Qƈ且关注于对SQLException转换为适当的DataAccessExceptionQ包括对Ҏ的数据库SQL错误转换为有意义的异常?l由不同的事务管理对象,Spring支持JTA和JDBC事务。Spring 也提供对Hibernate和JDO的支持,它的q种支持׃JdbcTemplatecȝ作用相类似的HibernateTemplatecdJdoTemplatec? 以及HibernateInterceptorcRJdoInterceptorc,q有Hibernate、JDO 事务理cȝ成?/font>

       最主要的目的是要应用的层ơ分明,为此数据访问和事务处理同应用对象分d来。所有的业务对象都不再依赖数据访问或者事务策略。不再有编码的资源查找代码Q不再有难以替换的单例对象,也不再需要定制服务注册?/font>

      所有的单独的数据访问特性均无需依赖于SpringQ可以单独用,无需让Spring知道Q同时也可以通过Spring的应用配|(提供ZXML的配|和Ҏ通JavaBean实例的交叉引用)来进行装配。在一个典型的Spring应用中,大部分重要的对象都是普通的JavaBeanQ数据访问模板对象(data access templatesQ、数据访问对象(使用数据讉K模板对象的对象)、事务管理对象及业务对象Q用数据访问对象和事务对象的对象)Qweb表示分解对象、web控制对象Q用业务对象的对象Q等{?/font>

2. 应用配置中的资源定义

    Z避免应用对象资源查扄代码编码,Spring允许在应用配|中一个如JDBC DataSource或者Hibernate SessionFactory定义Z个Bean。应用对象如果需要访问资源只需要通过Bean引用QDAO定义在下一部分说明Q接受先前定义的实例的引用。以下的内容引用自一个应用配|定义,昄了如何徏立一个JDBC DataSource和一个Hibernate的SessionFactoryQ?/font>

 <beans>

<bean id="myDataSource" class="org.springframework.jndi

.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/myds</value>
</property>
</bean>

<bean id="mySessionFactory" class="org.springframework.orm.hibernate

.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect

.MySQLDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource"/>
</property>
</bean>

...

</beans>

      注意选择是用JNDI来定位数据源q是从一个象Jakarta Commons DBCP BasicDataSourceq样的本地定义取得一个数据源Q只是一个改变配|的事:

<bean id="myDataSource"
      class="org.apache.commons

.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost:9001</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>

       你也可以使用一个JNDI查找SessionFactoryQ但是通常对于EJB环境之外的应用来说ƈ不是需要的Q参?container resources vs local resources"部分的讨论)?/font>

3. 倒置控制QInversion of ControlQ? 模板和回?/font>

    模板的基本编E模式就象你在下面看到那样Q至于方法就如同M定制的数据访问对象或者业务的对象的方法一栗除了需要向其提供一个Hibernate的SessionFactory之外Q再没有对周围执行对象的信赖的限制。虽然最好是从一个Spring的应用配|中l由一个简单setSessionFactory bean的属性设|用Bean引用来获得它Q但随后你可以从M地方获得它。随后的引用片段包括一D在Spring应用配置中对DAO定义的配|,其中引用了在其前面定义的SessionFactoryQ和一DDAOҎ的实现的例子?/font>

<beans>

<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

...

</beans>

public class ProductDaoImpl implements ProductDao {

private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory 
   sessionFactory) {
this.sessionFactory = sessionFactory;
}

public List loadProductsByCategory(final String 
  category) {
HibernateTemplate hibernateTemplate =
new HibernateTemplate(this.sessionFactory);

return (List) hibernateTemplate.execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws
 HibernateException {
List result = session.find(
"from test.Product product where product.category=?",
category, Hibernate.STRING);
// do some further stuff with the result list
return result;
}
}
);
}
}

       一个回调的实现可以被有效地用在MHibernate数据讉K中。在M情况下都由HibernateTemplate来管理Session的开闭和自动的多方事务。模板实例是U程安全和可重用的,因此它们可以做ؓ其他cȝ变量?/font>


       对于单的单步的动作,象find, load, saveOrUpdate或者delete的调用,HibernateTemplate提供更ؓ便利的选择以代替象一行的回调的执行。此外,Spring提供了一个方便的基本c,是HibernateDaoSupportc,它提供了setSessionFactoryҎ来接受一个SessionFactoryQ同时提供了getSessionFactory和getHibernateTemplateҎ供其l承cM用。将q些l合hQ允许对于典型的需求给Z非常单的DAO实现Q?/font>

public class ProductDaoImpl extends HibernateDaoSupport implements
 ProductDao {

public List loadProductsByCategory(String category) {
return getHibernateTemplate().find(
"from test.Product product where product.category=?", category,
Hibernate.STRING);
}
}

4. 应用一个AOP拦截器代替一个模?/font>

   除用HibernateTemplate之外的另一个选择是使用Spring的AOP HibernateInterceptor。用直接在一个委托的try/catch块中~写Hibernate代码Q配合相应的在应用配|中分别的拦截器配置来代替执行回调。下面的片段昄了一个Spring应用配置中的DAO, interceptor和proxy的各自的定义Q同时给Z一个DAOҎ实现的例子:

<beans>

...

<bean id="myHibernateInterceptor"
      class="org.springframework.orm.hibernate
.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

<bean id="myProductDaoTarget" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

<bean id="myProductDao" class="org.springframework.aop
.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductDao</value>
</property>
<property name="interceptorNames">
<list>
<value>myHibernateInterceptor</value>
<value>myProductDaoTarget</value>
</list>
</property>
</bean>

...

</beans>

 
public class ProductDaoImpl extends HibernateDaoSupport 
   implements ProductDao {

public List loadProductsByCategory(final String category)
 throws MyException {
Session session = SessionFactoryUtils
.getSession(getSessionFactory(), false);
try {
List result = session.find(
"from test.Product product where product.category=?",
category, Hibernate.STRING);
if (result == null) {
throw new MyException("invalid search result");
}
return result;
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
}

        q个Ҏ只在有一个与它配合的HibernateInterceptor时才能正常工作,HibernateInterceptor为它负责在方法调用前U程l定Session的开启和Ҏ调用后的关闭。getSessionҎ调用中的"false"标志是要认Session必须是已l存在的Q如果没有发CQ何一个SessionQSessionFactoryUtils会为其创徏一个。如果已l有一个Session句柄l定在本U程上,比如是由一个HibernateTransactionManager事务l定的,在Q何情况下SessionFactoryUtils会自动接入这个Session。HibernateTemplate在底层也使用SessionFactoryUtilsQ与以上说的方式基本是一L?/font>

       HibernateInterceptor的主要益处是它允许在数据讉K代码中抛出checked application exceptionQ而HibernateTemplate׃受限于回调只能在其中抛出unchecked exceptions。注意到q点我们可以推迟各自的检验,同时在回调后抛出应用异常。拦截方式的主要~点是它需要在配置中进行特D的配置。HibernateTemplate在大多数情况下都是一U简单好用的Ҏ?br />

5. E序事务划分

   在这U底层的数据讉K服务之上Q事务处理可以在更高的应用层被划?QŞ成一些操作。这里除了需要一个Spring的PlatformTransactionManager对象外,对于周围q行的业务对象也没有M限制。同LQ其后你可以从Q何地方获得它们,但是l由Bean引用的方式通过setTransactionManageҎ获得更ؓ适合Q象productDAO要经׃个setProductDaoҎ获得一栗下面的引用片段昄了在一个Spring应用配置中的事务理对象和业务对象的定义Qƈ且还提供了一个业务方法实现的例子Q?/font>

<beans>

...

<bean id="myTransactionManager"
      class="org.springframework.orm.hibernate
.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

<bean id="myProductService" class="product.ProductServiceImpl">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>

</beans>

 
public class ProductServiceImpl implements ProductService {

private PlatformTransactionManager transactionManager;
private ProductDao productDao;

public void setTransactionManager(PlatformTransactionManager 
  transactionManager) {
this.transactionManager = transactionManager;
}

public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}

public void increasePriceOfAllProductsInCategory(final String 
  category) {
TransactionTemplate transactionTemplate =
new TransactionTemplate(this.transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition
    .PROPAGATION_REQUIRED);
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus 
  status) {
List productsToChange = productDAO.loadProductsByCategory(category);
...
}
}
);
}
}

6. 声明性事务划?/font>

       我们q可以选择使用Spring的AOP TransactionInterceptor通过在应用配|中定义拦截器配|来代替事务划分代码的事务处理方式。这允许我们保持业务对象独立于每个业务对象中重复的事务划分代码。此外,事务行ؓ和隔dơ的变化可以通过一个配|文件来改变而不需要对业务对象的实现造成影响?/font>

<beans>

...

<bean id="myTransactionManager"
      class="org.springframework.orm.hibernate
.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

<bean id="myTransactionInterceptor"
      class="org.springframework.transaction
.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="transactionAttributeSource">
<value>
product.ProductService.increasePrice*=PROPAGATION_REQUIRED
product.ProductService.someOtherBusinessMethod=
PROPAGATION_MANDATORY
</value>
</property>
</bean>

<bean id="myProductServiceTarget" class="product
.ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>

<bean id="myProductService" class="org.springframework.aop
.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductService</value>
</property>
<property name="interceptorNames">
<list>
<value>myTransactionInterceptor</value>
<value>myProductServiceTarget</value>
</list>
</property>
</bean>

</beans>

 
public class ProductServiceImpl implements ProductService {

private ProductDao productDao;

public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}

public void increasePriceOfAllProductsInCategory(final String
 category) {
List productsToChange = this.productDAO
.loadProductsByCategory(category);
...
}
}

      如同使用HibernateInterceptor一PTransactionInterceptor允许Mchecked application exception从回调代码中抛出Q而TransactionTemplate受回调限制在其内部抛出unchecked exceptionsQ在出现一个unchecked application exception的情冉|QTransactionTemplate引发一个回滚或者这个事务由应用Q通过事务状态)标记为回滚。TransactionInterceptor默认情况也是同样的行为,但是允许为每一个方法制定回滚策略?br />       建立声明性事务的一个便利的方式是用TransactionProxyFactoryBeanQ特别是如果没有其他AOP拦截器的话,TransactionProxyFactoryBean联合定义ؓ代理的自w与一个特D的目标Bean的事务配|。这减一个代理Bean对应一个目标Bean的配|情c此外,你不必指定哪个接口或者哪个类必须定义事务Ҏ?/font>

<beans>

...

<bean id="myTransactionManager"
      class="org.springframework.orm.hibernate
.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>

<bean id="myProductServiceTarget" class="product
.ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>

<bean id="myProductService"
      class="org.springframework.transaction.interceptor
.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>

</beans>

7. 事务理{略

          对于Hibernate应用来说Q无论是TransactionTemplateq是TransactionInterceptor都是委托验实际的事务处理lPlatformTransactionManager实例Q可以是一个HibernateTransactionManagerQ由一个单一的Hibernate的SessionFactoryQ用一个ThreadLocal SessionQ或者可以是一个JtaTransactionManagerQ代理容器的JTA子系l)。甚至你可以使用一个自定义的PlatformTransactionManager实现?br />       如果选择从本地Hibernate事务理转ؓ由JTA来进行事务管理,例如Q当你的应用的部|面对分布的事务需求时Q也仅仅是改变一下配|的事。只要简单地Hibernate的事务管理换为JTA事务实现卛_。所有的事务划分和数据访问无需做Q何变动仍可以l箋工作Q因Z们用的都是普通的事务理API?br />       对于分布式的事务会跨多个Hibernate的session factoriesQ仅仅是联合JtaTransactionManager与多个LocalSessionFactoryBean定义作ؓ事务{略。你的每一个DAO通过它们各自的Bean属性得C个特D的SessionFactory的引用。如果这一切都是在下面的JDBC数据源是事务容器Q一个业务对象可以划分事务跨很多DAO和很多session factories而无需做特别的处理Q对于用JtaTransactionManager做ؓ事务{略也是一L?/font>

 
<beans>

<bean id="myDataSource1" class="org.springframework.jndi
.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/myds1</value>
</property>
</bean>

<bean id="myDataSource2" class="org.springframework.jndi.
JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/myds2</value>
</property>
</bean>

<bean id="mySessionFactory1"
      class="org.springframework.orm.hibernate.
LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.
MySQLDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource1"/>
</property>
</bean>

<bean id="mySessionFactory2"
      class="org.springframework.orm.hibernate.
LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>inventory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.
dialect.OracleDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource2"/>
</property>
</bean>

<bean id="myTransactionManager"
      class="org.springframework.transaction.jta.
JtaTransactionManager"/>

<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory1"/>
</property>
</bean>

<bean id="myInventoryDao" class="product.InventoryDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory2"/>
</property>
</bean>

<bean id="myProductServiceTarget" class="product.
ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
<property name="inventoryDao">
<ref bean="myInventoryDao"/>
</property>
</bean>

<bean id="myProductService"
      class="org.springframework.transaction.interceptor.
TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>

</beans>

       无论是HibernateTransactionManagerq是JtaTransactionManager允许适当的对Hibernate的在JVM层次的缓存处?不需要容?提供Ҏ的事务查找或者JCAq接器(只要不用EJB发v事务Q。另外,HibernateTransactionManager能输出JDBCq接供通常的JDBC讉K代码使用。这样就允许在高层次上的事务划分是؜合了Hibernate与JDBC而不要JTA的,只要只是讉K一个数据库可以!

8. 使用Spring理应用的Bean

        一个Spring应用配置定义可以被多U配|实现所加蝲Q从FileSystemXmlApplicationContext和ClassPathXmlApplicationContext到XmlWebApplicationContext。这允许在各种环境下重用Spring理的数据访问和业务对象。默认情况下Q一个Web应用有它自q定义在“WEB-INF/applicationContext.xml”中的根配置?br />       在Q何一个Spring应用中,一个应用配|定义在一个XML格式的文件中用来对应用的所有有关的Beanq行装配Q从Hibernate的session factory到自定义的数据访问和业务对象Q象上面所有的Bean那样Q。他们中的大多数不需要Spring容器知道他们Q甚臛_使是与其他Bean合作时也一P因ؓ他们只是单的JavaBean之间的协作。下面的Bean定义可能是一个Spring Web 的MVC配置中用来访问业务对象的配置的一部分?/font>

 
<bean id="myProductList" class="product.ProductListController">
<property name="productService">
<ref bean="myProductService"/>
</property>
</bean>

      Spring的Web控制器经由Bean引用拥有它们需要的所有的业务和数据访问对象,因此它们无需在应用配|中做Q何手工的Bean查找。但是当使用Spring理的Beans用于Struts或者是在EJB实现Q或者一个applet中时常常是需要必L工查找一个Bean的。因此Spring的Bean可以被用在Q何地斏V也许只是需要是一应用配置的引用,或者经׃个web容器的Servlet配置属性,或者从一个文件中或者类路径的资源中创徏它?/font>

ApplicationContext context =WebApplicationContextUtils.
getWebApplicationContext(servletContext);
ProductService productService =
(ProductService) context.getBean("myProductService");

 ApplicationContext context =
new FileSystemXmlApplicationContext("C:/myContext.xml");
ProductService productService =
(ProductService) context.getBean("myProductService");

 ApplicationContext context =
new ClassPathXmlApplicationContext("myContext.xml");
ProductService productService =
(ProductService) context.getBean("myProductService");

9. 容器资源VS本地资源

       Spring的资源管理允许简单地在一个JNDI SessionFactory和一个本地SessionFactory间做选择Q同样允许在一个JNDI DataSource与本地DataSource间做选择Q而无需改变应用的一行代码。在容器中保存资源定义还是在应用本地保存Q主要是一个事务策略方面的事。比较一个Spring定义的本地SessionFactory与一个手工注册的JNDI SessionFactory没有M益处。如果经由Hibernate的JCAq接器注册,才会有加入JTA事务的明昄处,特别是对EJB?/font>

       一个重要的Spring事务提供的好处是它不与Q何容器绑定。定义包括JTA在内的策略,它都可以独立工作或者在一个试验环境中工作。特别是对典型的一个数据库的事务来_对于JTAq是一个非常轻量的和强大的选择。当使用本地EJB SLSB的事务时Q你同时依赖EJB容器和JTA-即你只是访问一个数据库Q即使只是用SLSBsl由CMT来声明事务。选择使用 JTA~程也需要一个J2EE环境?/font>

       JTA自n和JNDI数据源来说JTA不只是包括容器依赖。对于不使用Spring的JTA驱动的Hibernate事务Q你必须使用HibernateJCAq接器或者在合适的JVM~冲层专门写Hibernate的事务代码配|JTA事务。在只访问一个数据库的情况下QSpring驱动的事务可以与一个本地定义的Hibernate的SessionFactory配合良好Q就如同与一个本地JDBC数据源相配合一栗因此当面对分布的事务需求时Q你只需要{换ؓSpring的JTA事务{略卛_?

       要注意一个JCAq接器需要特别的容器的部|步骤,q且昄首先得支持JCA。这比用本地资源定义和Spring驱动事务来部|一个简单的Web应用有更多的争议。而且你常帔R要企业版本的容器支持Q象WebLogic Express׃提供JCA。一个只用一个数据库的用本地资源和事务的Spring应用可以在Q何J2EE的Web容器中工作,Web容器不必支持JTA, JCA和EJBQ如QTomcat, Resin甚至最的Jetty。另外,q样一个中间层可以很Ҏ地在桌面应用或者在试套g中被重用?/font>

       所有考虑q的事情包括Q如果你不用EJBQ坚持用本地SessionFactoryQ用SpringHibernateTransactionManager或者JtaTransactionManagerQ你获得包括适当处理的JVM层的~存和分布事务的所有益处,而无需引vM关于容器部v的争论。经由JCAq接器的一个Hibernate的SessionFactory的JNDI注册只是在用EJB的情况中才会有明昄附加倹{?/font>


10. Skeletons和例?/font>

      配置使用Spring和HIbernate的一个J2EE的Web应用的注释和l节最好去看看在Spring Framework的例子中的“典型的Web应用”SkeletonsQ它l出了适合于JDBC ?Hibernate应用的多U数据源及事务管理的配置,仔细看一下事务拦截器的配|,它也同样向你展示了如何配|AOP拦截器?/font>

      在Spring?.0 M2版中Q例子Petclinic提供了JDBC和Hibernate的DAO实现和应用配|的选择。Petclinic
可以作ؓ一个可工作的简单应用说明如何在一个Spring web 应用中用HibernateQ同样也包括Ҏ不同的事务策略来声明事务划分?br />

Links

Spring Framework website

Spring Framework documentation



rendong 2006-08-01 13:54 发表评论
]]> վ֩ģ壺 ׾Ʒר| ޾ƷŮþ7777777 | ޾ƷƵ| Ʒ鶹ѹۿ| Ļ߹ۿ| ձ| Ļ߹ۿ| ˳һ| ձһ岻| һ2342021ѹۿ һ234޿Ƶ | ݾ߹ۿվ| ޹˳߹ۿ| ޹Ʒ˾Ʒ | ߹ۿѹۿַ| ˳վɫ߹ۿ| vavava| ޳777777Ʒ| ձѹۿվ| ޾þһح | ѹվ߹ۿ | ޾ƷƵ| ۺɫƵ߹ۿ| һ | av߹ۿַ| av뾫Ʒ4| 18ͬ־videosվ| AVۺɫһ| ɫ͵͵ۺAVYP| Ƭһ| ޳˹Ʒ| ޾Ʒר2| ձһ| һȫëƬ| ѹaƬ| һƷһaһ| ߹ۿվ| 18վѹۿ| պƷר߹ۿ| պƷһ| ۺϼר| һĻ|