﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-我的Blog，我的舒亭-文章分类-spring</title><link>http://www.blogjava.net/Aisce/category/25573.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 16 Nov 2007 08:24:18 GMT</lastBuildDate><pubDate>Fri, 16 Nov 2007 08:24:18 GMT</pubDate><ttl>60</ttl><item><title>spring配置文件详解</title><link>http://www.blogjava.net/Aisce/articles/160650.html</link><dc:creator>Aisce</dc:creator><author>Aisce</author><pubDate>Wed, 14 Nov 2007 15:47:00 GMT</pubDate><guid>http://www.blogjava.net/Aisce/articles/160650.html</guid><wfw:comment>http://www.blogjava.net/Aisce/comments/160650.html</wfw:comment><comments>http://www.blogjava.net/Aisce/articles/160650.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Aisce/comments/commentRss/160650.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Aisce/services/trackbacks/160650.html</trackback:ping><description><![CDATA[
		<div class="ad">
				<script type="text/javascript">
						<!--
google_ad_client = "pub-3178351830176495";
google_ad_width = 336;
google_ad_height = 280;
google_ad_format = "336x280_as";
google_ad_type = "text_image";
//2007-11-10: kudee
google_ad_channel = "7733316921";
google_color_border = "F9FCFE";
google_color_bg = "F9FCFE";
google_color_link = "1F3A87";
google_color_text = "525253";
google_color_url = "525253";
//-->
				</script>
				<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
				</script>
				<iframe name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-3178351830176495&amp;dt=1195055192296&amp;lmt=1194703233&amp;format=336x280_as&amp;output=html&amp;correlator=1195055192296&amp;channel=7733316921&amp;url=http%3A%2F%2Fwww.kudee.cn%2Fhtml%2FDevelop%2FSpring%2F20070916%2F2237.html&amp;color_bg=F9FCFE&amp;color_text=525253&amp;color_link=1F3A87&amp;color_url=525253&amp;color_border=F9FCFE&amp;ad_type=text_image&amp;ref=http%3A%2F%2Fwww.kudee.cn%2Fhtml%2FDevelop%2FSpring%2F20070916%2F2238.html&amp;cc=100&amp;ga_vid=1740814352.1195055192&amp;ga_sid=1195055192&amp;ga_hid=864633806&amp;flash=9&amp;u_h=768&amp;u_w=1024&amp;u_ah=738&amp;u_aw=1024&amp;u_cd=32&amp;u_tz=480&amp;u_his=6&amp;u_java=true" frameborder="0" width="336" scrolling="no" height="280" allowtransparency="">
				</iframe>
		</div>
		<style><![CDATA[.Kgd244 { display:none; } ]]&gt;</style>
Spring有四种Bean封装机制：Bean Wrapper机制、Bean Factory机制、ApplicationContext机制、Web Context机制等，它们所对应配置文件的内容也是不同的。下面，我们就以基于Bean Factory机制实现的Spring的三种依赖注入模式为例，介绍一下Spring配置文件的基本内容。<br />     1、接口注入，示例代码如下：<br />public interface InterfaceB{<br />public Object doIt();<br />} 
<div>public class ClassC implements InterfaceB{<br />String str1;<br />public ClassC(String str1){<br />This. str1= str1;<br />}<br />public Object doIt(){<br />return "Hello,"+ strl+"!";<br />}<br />}</div><div>public class ClassA {<br />private InterfaceB clzB;<br />public Object doSomething(InterfaceB b) {<br />clzB = b;<br />return clzB.doIt();<br />}<br />………<br />}<br />该情况下的Spring配置文件：bean.xml的内容大致如下：<br />&lt;beans&gt;<br />&lt;description&gt;Interface Injection Sample&lt;/description&gt;<br />&lt;bean id="ClassC" <strong>&lt;!--ClassC类的别名 --&gt;</strong><br />class="net.liyb.spring.qs.ClassC"&gt; <strong>&lt;!--ClassC类的别名所对应的类 --&gt;</strong><font color="#ffffff">字串3</font><br />&lt;property name="str1"&gt; <strong>&lt;!-- 该属性名对应ClassC类的属性（名称一致） --&gt;</strong><br />&lt;value&gt;liyb&lt;/value&gt; <strong>&lt;!-- 该属性值将被绑定到ClassC类的对应属性（str1）上 --&gt;</strong><br />&lt;/property&gt;<br />&lt;/bean&gt;</div><div>&lt;bean id="ClassA" <strong>&lt;!-- ClassA类的别名 --&gt;</strong><br />class="net.liyb.spring.qs.ClassA"&gt; <strong>&lt;!--ClassA类的别名所对应的类 --&gt;</strong><br />&lt;property name="clzB"&gt; <strong>&lt;!-- 该属性名对应ClassA类的属性（名称一致） --&gt;</strong><br />&lt;ref local="ClassC"/&gt; <strong>&lt;!-- 该属性值将被绑定到ClassA类的对应属性（clzB）上，此处的属性值即"别名"为ClassC所对应的类的实例 --&gt;</strong><br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;/beans&gt;<br />     2、设值注入，示例代码如下：<br />public class DIByConstructor {<br />private final DataSource dataSource;<br />private final String message;<br />……… 
<div class="Kgd244">字串8</div><br />public setDataSource(DataSource ds) {<br />this.dataSource = ds;<br />}<br />public setmessage(String msg) {<br />this.message = msg;<br />}<br />public getDataSource() {<br />return this.dataSource;<br />}<br />public getmessage() {<br />return this.message;<br />}<br />………<br />}<br />该情况下的Spring配置文件：bean.xml的内容大致如下：<br />&lt;beans&gt;<br />&lt;description&gt;Values Injection Sample&lt;/description&gt;<br />&lt;bean id="dataSource" <strong>&lt;!-- JndiObjectFactoryBean类的别名 --&gt;</strong><br />class="org.springframework.jndi.JndiObjectFactoryBean"&gt; <strong>&lt;!-- JndiObjectFactoryBean类的别名所对应的类 --&gt;</strong><br />&lt;property name="jndiName"&gt; <strong>&lt;!-- 该属性名对应JndiObjectFactoryBean类的属性（名称一致） --&gt;</strong><br />&lt;value&gt;java:comp/env/jdbc/sample&lt;/value&gt; <strong>&lt;!-- 该属性值将被绑定到JndiObjectFactoryBean类的对应属性（jndiName）上 --&gt;</strong><br />&lt;/property&gt;<br />&lt;/bean&gt;</div><div>&lt;bean id="DIByConstructor" <strong>&lt;!--DIByConstructor类的别名 --&gt;</strong><p class="Kgd244">字串8</p><br />class="net.liyb.spring.qs.DIByConstructor"&gt; <strong>&lt;!--DIByConstructor类的别名所对应的类 --&gt;</strong><br />&lt;property name="message"&gt; <strong>&lt;!-- 该属性名对应DIByConstructor类的属性（名称一致） --&gt;</strong><br />&lt;value&gt;HeLLo&lt;/value&gt; <strong>&lt;!-- 该属性值将被绑定到DIByConstructor类的对应属性（message）上--&gt;</strong><br />&lt;/property&gt;<br />&lt;/bean&gt;</div><div>&lt;bean id="DIByConstructor" <strong>&lt;!--DIByConstructor类的别名 --&gt;</strong><br />class="net.liyb.spring.qs.DIByConstructor"&gt; <strong>&lt;!--DIByConstructor类的别名所对应的类 --&gt;</strong><br />&lt;property name="dataSource"&gt; <strong>&lt;!-- 该属性名对应DIByConstructor类的属性（名称一致） --&gt;</strong><br />&lt;ref local="dataSource"/&gt; <strong>&lt;!-- 该属性值将被绑定到DIByConstructor类的对应属性（dataSource）上，此处的属性值即"别名"为dataSource所对应的类的实例--&gt;</strong><br />&lt;/property&gt;<br />&lt;/bean&gt;</div><div>&lt;/beans&gt; <span class="Kgd244">字串4</span><br />     3、构造子注入，示例代码见日志："Spring核心技术学习总结"中的1.2.3节。此时对应的配置文件同"2、设值注入"中的配置文件是一样的，所以具体内容在此省略。</div><img src ="http://www.blogjava.net/Aisce/aggbug/160650.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Aisce/" target="_blank">Aisce</a> 2007-11-14 23:47 <a href="http://www.blogjava.net/Aisce/articles/160650.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring下的单元测试要点</title><link>http://www.blogjava.net/Aisce/articles/151964.html</link><dc:creator>Aisce</dc:creator><author>Aisce</author><pubDate>Thu, 11 Oct 2007 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/Aisce/articles/151964.html</guid><wfw:comment>http://www.blogjava.net/Aisce/comments/151964.html</wfw:comment><comments>http://www.blogjava.net/Aisce/articles/151964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Aisce/comments/commentRss/151964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Aisce/services/trackbacks/151964.html</trackback:ping><description><![CDATA[
		<h2>1. 需要Spring 依赖注入的测试</h2>
		<p>   为了测试Spring管理下的Bean，可以自行构造BeanFactory，也可以继承于<span class="nobr"><a title="Visit page outside Confluence" href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/test/AbstractDependencyInjectionSpringContextTests.html" rel="nofollow">AbstractDependencyInjectionSpringContextTests</a></span>，实现public String[] getConfigLocations()函数， 返回applicationContext文件路径的数组。</p>
		<div class="code">
				<div class="codeContent">
						<pre class="code-java"> <span class="code-keyword">protected</span><span class="code-object">String</span>[] getConfigLocations() {
        <span class="code-keyword">return</span><span class="code-keyword">new</span><span class="code-object">String</span>[]{<span class="code-quote">"classpath*:spring/*.xml"</span>,  <span class="code-quote">"classpath*:spring/test/*.xml"</span>};
 } </pre>
				</div>
		</div>
		<p>  并显式写一些需要注入的变量的setter函数。</p>
		<p>    tips1：此基类有一个applicationContext的成员变量，所以除了依靠setter注入外，还可以随时用applicationContext.getBean() 取出所需的bean。 </p>
		<p>    tips2：注意此基类 默认是autowire by type的，所以如果context文件里有两个相同类型的Bean就会报错，可能需要在getConfigLocations()函数里，setAutowireMode(AUTOWIRE_BY_NAME);把它设回by name，或者取消setter函数，自行用applicationContext.getBean()来显式查找Bean。</p>
		<h2>
				<a name="SpringUnitTest-2.Dao%E6%B5%8B%E8%AF%95">
				</a>2. Dao测试</h2>
		<p>
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/test/AbstractTransactionalDataSourceSpringContextTests.html" rel="nofollow">AbstractTransactionalDataSourceSpringContextTests</a>
				</span> 继承于AbstractDependencyInjectionSpringContextTests，除了拥有上类的能力外，还管理了每个测试的事务，会在每个测试后默认回滚所有的操作。</p>
		<p>深层解释：此类的实现其实依赖于Application Context中定义的 <tt>PlatformTransactionManager</tt>。由于使用了Autowrie by type，可以任意取名。</p>
		<p>         另依赖于Application Context中定义的<tt>DataSource，同样可以任意取名。</tt> </p>
		<p>tips1：如果需要在测试后提交，需要setRollBack(false); 或者调用setComplete()</p>
		<p>tips2：此基类还通过注入的DataSource创建了一个JDBCTemplate 变量，可以跑SQL帮忙核对Hibernate的结果，Spring将确保该查询在同一个事务内执行。为正常工作你需要告诉你的ORM工具'刷新'它的已改变内容，例如使用Hibernate <tt>Session</tt> 接口的 <tt>flush()</tt> 方法。</p>
		<p>tips3：除了tips2以外，还有countRowsInTable(String tableName)，deleteFromTables(String[] names) ，executeSqlScript(String sqlResourcePath, boolean continueOnError)三个简便函数。</p>
		<h2>
				<a name="SpringUnitTest-3.Controller%E6%B5%8B%E8%AF%95">
				</a>3. Controller测试</h2>
		<p>Controller测试一般要用MockObject 分离Service层，要copy WEB-INF/下的相关文件copy 到classpath，而且Controller不含太多的逻辑，所有测试controller有点吃力不讨好，建议直接用Selenium进行集成测试，见(<a title="Selenium" href="http://wiki.springside.org.cn/display/springside/Selenium">Selenium测试概述</a>)。</p>
		<h2>
				<a name="SpringUnitTest-4.SpringSide%E9%87%8C%E7%9A%84%E6%B5%8B%E8%AF%95">
				</a>4.SpringSide里的测试</h2>
		<p>因为Spring默认的基类名字较长，<a href="http://www.springside.org.cn/">SpringSide </a>在core 的org.springside.core.test 中重新继承了它们，并提供了默认读取所有按springside 文件存放规则存放的context 文件的getConfigLocations()函数。</p>
		<p>默认读取所有context文件的getConfigLocations()函数对速度和测试的隔离化都有影响，可以在子类重新实现。不过自己重新一个个写相关context文件也好烦，而且其实在全lazy-load的情况下，速度也还可以接受。如何取舍要自己平衡了。</p>
		<p>对于CRUD的测试，在helloworld示例里的变量名都作了泛化，可以快速copy到另一个测试里。</p>
		<p>另外，留意resources/spring/test 下的文件，利用了Spring的<span class="nobr"><a title="Visit page outside Confluence" href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/beans/factory/config/PropertyOverrideConfigurer.html" rel="nofollow">PropertyOverrideConfigurer<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a></span>，新设定测试时的ApplicatonContext 里各个Bean的属性如指定测试用的DataSource，详细用法见<a title="SpringConfig" href="http://wiki.springside.org.cn/display/springside/SpringConfig">Spring配置要点</a>。</p>
<img src ="http://www.blogjava.net/Aisce/aggbug/151964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Aisce/" target="_blank">Aisce</a> 2007-10-11 10:24 <a href="http://www.blogjava.net/Aisce/articles/151964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让Spring架构减化事务配置</title><link>http://www.blogjava.net/Aisce/articles/142810.html</link><dc:creator>Aisce</dc:creator><author>Aisce</author><pubDate>Wed, 05 Sep 2007 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/Aisce/articles/142810.html</guid><wfw:comment>http://www.blogjava.net/Aisce/comments/142810.html</wfw:comment><comments>http://www.blogjava.net/Aisce/articles/142810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Aisce/comments/commentRss/142810.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Aisce/services/trackbacks/142810.html</trackback:ping><description><![CDATA[
		<p>让Spring架构减化事务配置<br />注：原创文章,本文曾发表于it168<br />Spring颠覆了以前的编程模式，引入了IOC等全新的概念，广受大家的喜爱。目前大多数j2ee项目都已经采用Spring框架。 Spring最大的问题是太多的配置文件，使得你不仅需要维护程序代码，还需要额外去维护相关的配置文件。最典型的就是事务配置(注：这里的"事务配置" 都指"声明式事务配置")，在Spring中进行事务配置除了定义对象自身的bean外，还需要定义一个进行事务代理的bean.如果你有n个类需要引入事务，那么你就必须定义2n个bean。维护这些bean的代价是十分昂贵的，所以必须要对事务配置进行减化。如果你是基于Spring进行架构设计，那么作为一个好的架构设计师，应该把一些公共的方面进行简化，让项目的开发人员只关心项目的业务逻辑，而不要花费太多的精力去关心业务逻辑之外的太多东西。所以作为一个好的架构就应该把事务管理进行简化，让程序员花在编程之外的工作最小化。<br />1. Spring声明式事务配置的几种方法<br />在Spring中进行事务控制首先要选择适当的事务管理器，其次为程序选择划分事务的策略。如果只有单个事务性资源，可以从"单一资源"的 PlatformTransactionManger实现当中选择一个，这些实现有：DataSourceTransactionManager, HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和 JmsTransactionManager。根据你所采用的数据库持久化技术选择。如果你的项目运行于支持JTA的服务器，那么将选择 JtaTransactionManger，将会支持多资源事务。<br />下表将为你选择适当的事务管理器提供参考。<br />技术 事务管理器 内建的事务支持<br />JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有类<br />IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate<br />Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor<br />JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor<br />ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate<br />JMS JmsTransactionManager JmsTemplate</p>
		<p>在划分事务时，我们需要进行事务定义，也就是配置事务的属性。事务的属性有传播行业，隔离级别，超时值及只读标志。TransactionAttribute接口指定哪些异常将导致一个回滚，哪些应该一次性提交。</p>
		<p>(1) 使用ProxyFactoryBean 和TransactionInterceptor</p>
		<p>&lt;!--定义本地数据源--&gt;</p>
		<p>&lt;bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;<br />&lt;property name="driverClassName" value="${jdbc.driverClassName}"/&gt;<br />&lt;property name="url" value="${jdbc.url}"/&gt;<br />&lt;property name="username" value="${jdbc.username}"/&gt;<br />&lt;property name="password" value="${jdbc.password}"/&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-- !定义单个jdbc数据源的事务管理器--&gt;<br />&lt;bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;<br />&lt;property name="dataSource" ref="dataSource"/&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义拦截器--&gt;<br />&lt;bean id="transactionInterceptor"<br />class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager"/&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="find*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"<br />class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"&gt;<br />&lt;property name="userInfoDAO"<br />ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象的事务代理对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean"&gt;<br />&lt;property name="target"<br />ref="com.prs.application.ehld.sample.biz.service.sampleService.target"&gt;<br />&lt;/property&gt;<br />&lt;property name="interceptorNames"&gt;<br />&lt;value&gt;transactionInterceptor&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>通过ProxyFacgtoryBean和TransactionInterceptor组合使用，可以对事务进行更多的控制。所有需要事务控制的对象可以共享一个transactionInterceptor的事务属性。</p>
		<p>(2) 使用TransactionProxyFactoryBean</p>
		<p>&lt;!-定义业务对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"<br />class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"&gt;<br />&lt;property name="userInfoDAO"<br />ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象的事务代理对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"<br />abstract="true"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager"/&gt;<br />&lt;/property&gt;<br />&lt;property name="target"<br />ref="com.prs.application.ehld.sample.biz.service.sampleService.target" /&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="find*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>使用TransactionProxyFactoryBean需要为每一个代理对象都去定义自己的事务属性。</p>
		<p>(3) 使用TransactionProxyFactoryBean及abstract属性来简化配置<br />这种方工也是目前使用得最多的一种声明式事务配置方法</p>
		<p>
				<br />&lt;!--事务控制代理抽象定义 --&gt;<br />&lt;bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"<br />abstract="true"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager"/&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="find*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"<br />class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"&gt;<br />&lt;property name="userInfoDAO"<br />ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象的事务代理对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy"&gt;<br />&lt;property name="target"<br />ref="com.prs.application.ehld.sample.biz.service.sampleService.target"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>使用abstract属性，可以让代理对象可以共享一个定义好的事务属性，使配置简化。</p>
		<p>(4)使用BeanNameAutoProxyCreator<br />&lt;!-定义拦截器--&gt;<br />&lt;bean id="transactionInterceptor"<br />class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager"/&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="find*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义bean别名自动代理创建器--&gt;<br />&lt;bean id="autoProxyCreator"<br />class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;<br />&lt;property name="interceptorNames"&gt;<br />&lt;value&gt;transactionInterceptor&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="beanNames"&gt;<br />&lt;list&gt;<br />&lt;idref local="com.prs.application.ehld.sample.biz.service.sampleService"/&gt;<br />&lt;/list&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义业务对象--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService"<br />class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"&gt;<br />&lt;property name="userInfoDAO"<br />ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>使用BeanNameAutoProxyCreator可以由框架来提供适当的代理，由一个transactionInterceptor统一定义事务属性，只需要把需要事务控制的bean加到beannames的列表。<br />对于需要大量声明式事务的bean，BeanNameAutoProxyCreator是十分方便的。减少了代理bean的定义，还可以灵活的决定一个bean是否进行事务控制。</p>
		<p>上面四种方法是在Spring中常见的声明式事务配置方法，其中使用TransactionProxyFactoryBean及abstract属性进行配置是最常见的简化方法。<br />我们暂且把需要进行事务控制的bean叫事务bean.把依赖和调用它的bean叫做业务bean。对事务bean进行代理叫做事务代理bean.</p>
		<p>1． 使用ProxyFactoryBean 和TransactionInterceptor，可以由一个TransactionInterceptor统一定义事务属性，对于每一个事务bean都需要再定义一个事务代理bean。如果有n个事务bean，那么就需要定义和维护2n个bean。并且注入到业务bean的不是事务bean本身，而是要求用事务代理bean注入。这增加了理解的难度。<br />2．使用TransactionProxyFactoryBean需要为每一个事务代理bean都定义自己的事务属性，除了需要维护2n个bean外，还需要为每一个事务代理bean定义事务属性。可以说是最麻烦的。同样需要把事务代理bean注入到业务bean，增加了理解的难度和项目的复杂度。<br />3．使用TransactionProxyFactoryBean及abstract属性是对使用TransactionProxyFactoryBean的一种简单化配置，可以让所有的事务bean共享一致的事务属性定义。需要维护2n个bean，需要把事务代理bean注入到业务bean。<br />4． 使用BeanNameAutoProxyCreator最适合在框架中使用，只需要维护n个bean。也无需要事务代理bean。直接把事务bean注入业务bean中。但是它必须把需要事务控制的bean加到beanNames列表中。</p>
		<p>2．类型自动代理创建器BeanClassTypeAutoProxyCreator<br />得于BeanNameAutoProxyCreator的启示，BeanNameAutoProxyCreator可以实现框架来实现自动代理。它只是把需要代理的bean加入beanNames属性列表。大大的简化了代理的配置，减少了代理bean的定义，使用事务bean注入业务对象，而不是代理 bean注入，更合乎事务逻辑。BeanNameAutoProxyCreator仍然需要开发人员除了定义业务bean外，还需要关心事务的定义，当然已经简单了很多。如果能实现一个BeanClassTypeAutoProxyCreator，为它指定一个可以代理的ClassType列表，那么在 context中所有属于ClassType和其子类的bean都自动获得代理。<br />实现思路：<br />1．BeanNameAutoProxyCreator继承了AbstractAutoProxyCreator，去实现方法：<br />protected abstract Object[] getAdvicesAndAdvisorsForBean(<br />Class beanClass, String beanName, TargetSource customTargetSource)<br />在BeanNameAutoProxyCreator中的实现是判断beanName 是存在于beanNames列表，如果能找到则Object[]不对空。否则返回null。<br />所以BeanClassTypeAutoProxyCreator也应该继承AbstractAutoProxyCreator。<br />getAdvicesAndAdvisorsForBean方法的实现可以参照BeanNameAutoProxyCreator方法的实现<br />2．BeanClassTypeAutoProxyCreator需要有一个进行代理的ClassType列表，在bean进行初始化后就在context中查找类型为ClassType列表中类型的所有beanName.从而获得一个beanNames列表。<br />获得beanNames列表后就可以像BeanNameAutoProxyCreator一样实现自动代理了。<br />3．要想获得当前context，我们可以实现ApplicationContextAware接口。让BeanClassTypeAutoProxyCreator的bean可以获得当前context.<br />4． 要在bean进行初始化动作，可以实现InitializingBean接口，实现afterPropertiesSet,在这个方法中在context中根据classType查找获得相关的beanName的列表。<br />5． 写一个空接口，里面没有任何方法。需要事务代理的类实现这个空接口。</p>
		<p>这样，只需要把这个空接口的全类名作为BeanClassTypeAutoProxyCreator的classTypes参数值，然后所有需要代理的类都去实现这个接口就可以自动获得代理了。无再需要任何配置。这样就可以让程序员专心于业务逻辑的开发，而无需要去关心事务控制方法，就像是没有使用事务一样。</p>
		<p>完整的实现类如下：<br />BeanClassTypeAutoProxyCreator.java<br />/**<br />* 根据类型自动代理Creator<br />*<br />* @author yuanguangdong date: Jul 13, 2004<br />*/<br />public class BeanClassTypeAutoProxyCreator extends AbstractAutoProxyCreator<br />implements ApplicationContextAware, InitializingBean {</p>
		<p>/** Logger that is available to subclasses */<br />protected final Log logger = LogFactory.getLog(getClass());</p>
		<p>/** ApplicationContext this object runs in */<br />private ApplicationContext applicationContext;</p>
		<p>/** MessageSourceAccessor for easy message access */<br />private MessageSourceAccessor messageSourceAccessor;</p>
		<p>/**被代理的bean别名列表**/<br />private List beanNames;</p>
		<p>/**被代理的classType列表**/<br />private List classTypes;</p>
		<p>
				<br />//---------------------------------------------------------<br />//实现AbstractAutoProxyCreator的抽像方法<br />//---------------------------------------------------------<br />/**<br />* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean(java.lang.Class,<br />* java.lang.String, org.springframework.aop.TargetSource)<br />*/<br />protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass,<br />String beanName, TargetSource targetSource) throws BeansException {<br />if (this.beanNames != null) {<br />if (this.beanNames.contains(beanName)) {<br />return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;<br />}<br />}<br />return DO_NOT_PROXY;<br />}</p>
		<p>
				<br />//-------------------------------------------------------<br />//实现ApplicationContextAware接口方法<br />//-------------------------------------------------------<br />/**<br />* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)<br />*/<br />public void setApplicationContext(ApplicationContext context)<br />throws BeansException {<br />if (context == null &amp;&amp; !isContextRequired()) {<br />// Reset internal context state.<br />this.applicationContext = null;<br />this.messageSourceAccessor = null;<br />} else if (this.applicationContext == null) {<br />// Initialize with passed-in context.<br />if (!requiredContextClass().isInstance(context)) {<br />throw new ApplicationContextException(<br />"Invalid application context: needs to be of type ["<br />+ requiredContextClass().getName() + "]");<br />}<br />this.applicationContext = context;<br />this.messageSourceAccessor = new MessageSourceAccessor(context);<br />initApplicationContext();<br />} else {<br />// Ignore reinitialization if same context passed in.<br />if (this.applicationContext != context) {<br />throw new ApplicationContextException(<br />"Cannot reinitialize with different application context: current one is ["<br />+ this.applicationContext<br />+ "], passed-in one is [" + context + "]");<br />}<br />}<br />}</p>
		<p>/**<br />* Determine whether this application object needs to run in an<br />* ApplicationContext.<br />* &lt;p&gt;<br />* Default is "false". Can be overridden to enforce running in a context<br />* (i.e. to throw IllegalStateException on accessors if outside a context).<br />*<br />* @see #getApplicationContext<br />* @see #getMessageSourceAccessor<br />*/<br />protected boolean isContextRequired() {<br />return true;<br />}</p>
		<p>/**<br />* Determine the context class that any context passed to<br />* &lt;code&gt;setApplicationContext&lt;/code&gt; must be an instance of. Can be<br />* overridden in subclasses.<br />*<br />* @see #setApplicationContext<br />*/<br />protected Class requiredContextClass() {<br />return ApplicationContext.class;<br />}</p>
		<p>/**<br />* Return the ApplicationContext instance used by this object.<br />*/<br />public final ApplicationContext getApplicationContext()<br />throws IllegalStateException {<br />if (this.applicationContext == null &amp;&amp; isContextRequired()) {<br />throw new IllegalStateException(<br />"ApplicationObjectSupport instance [" + this<br />+ "] does not run in an ApplicationContext");<br />}<br />return applicationContext;<br />}</p>
		<p>/**<br />* Return a MessageSourceAccessor for the application context used by this<br />* object, for easy message access.<br />*<br />* @throws IllegalStateException<br />* if not running in an ApplicationContext<br />*/<br />protected final MessageSourceAccessor getMessageSourceAccessor()<br />throws IllegalStateException {<br />if (this.messageSourceAccessor == null &amp;&amp; isContextRequired()) {<br />throw new IllegalStateException(<br />"ApplicationObjectSupport instance [" + this<br />+ "] does not run in an ApplicationContext");<br />}<br />return this.messageSourceAccessor;<br />}</p>
		<p>public void setClassTypes(String[] classTypes) {<br />this.classTypes = Arrays.asList(classTypes);</p>
		<p>}</p>
		<p>/**<br />* Subclasses can override this for custom initialization behavior. Gets<br />* called by &lt;code&gt;setApplicationContext&lt;/code&gt; after setting the context<br />* instance.<br />* &lt;p&gt;<br />* Note: Does &lt;/i&gt;not&lt;/i&gt; get called on reinitialization of the context but<br />* rather just on first initialization of this object's context reference.<br />*<br />* @throws ApplicationContextException<br />* in case of initialization errors<br />* @throws BeansException<br />* if thrown by ApplicationContext methods<br />* @see #setApplicationContext<br />*/<br />protected void initApplicationContext() throws BeansException {</p>
		<p>}</p>
		<p>
				<br />//-----------------------------------<br />//实现InitializingBean接口方法<br />//-----------------------------------</p>
		<p>/**<br />* 查找指定classType的beanName列表<br />*/<br />private List getBeanNames(String classType) {<br />List beanNameList = null;<br />try {<br />String[] beanName = this.getApplicationContext()<br />.getBeanNamesForType(Class.forName(classType), true, false);<br />if (beanName != null) {<br />beanNameList = Arrays.asList(beanName);<br />}<br />} catch (ClassNotFoundException ex) {<br />throw new IllegalArgumentException("Class not found: "<br />+ ex.getMessage());<br />}</p>
		<p>return beanNameList;<br />}</p>
		<p>/**<br />*<br />* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()<br />*/<br />public void afterPropertiesSet() throws Exception {</p>
		<p>if (classTypes != null &amp;&amp; !classTypes.isEmpty()) {<br />beanNames = new ArrayList();<br />for (int i = 0; i &lt; classTypes.size(); i++) {<br />String classType = (String) classTypes.get(i);<br />List aList = getBeanNames(classType);<br />beanNames.addAll(aList);<br />}<br />}<br />if (logger.isDebugEnabled()) {<br />for (int i = 0; i &lt; beanNames.size(); i++) {</p>
		<p>logger.debug("printBean:" + (String) beanNames.get(i));</p>
		<p>}<br />}</p>
		<p>}<br />}</p>
		<p>3.使用BeanClassTypeAutoProxyCreator<br />3.1为了使用BeanClassTypeAutoProxyCreator，将为所有需要进行代理的类定一个接口。<br />package com.prs.application.ehld.biz.service;<br />public interface BaseService {</p>
		<p>}</p>
		<p>3.2 让需要代理的类实现或继承这个公共接口<br />package com.prs.application.ehld.sample.biz.service;<br />public interface SampleService extends BaseService {<br />public void setUserInfoDAO(UserInfoDAO userInfoDAO);<br />public void insertUserInfo(UserInfoDTO userInfo) throws BusinessServiceException;<br />}</p>
		<p>3.3 配置事务代理<br />&lt;!-定义拦截器--&gt;<br />&lt;bean id="transactionInterceptor"<br />class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager"/&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="find*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_SUPPORTS,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义类型自动代理创建器--&gt;<br />&lt;bean id="autoClassTypeProxyCreator"<br />class="com.prs.application.ehld.common.aotoproxy.BeanClassTypeAutoProxyCreator"&gt;<br />&lt;property name="interceptorNames"&gt;<br />&lt;value&gt;transactionInterceptor&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="classTypes"&gt;<br />&lt;list&gt;<br />&lt;value&gt;com.prs.application.ehld.biz.service.BaseService&lt;/value&gt;<br />&lt;/list&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>&lt;!-定义事务bean--&gt;<br />&lt;bean id="com.prs.application.ehld.sample.biz.service.sampleService"<br />class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"&gt;<br />&lt;property name="userInfoDAO"<br />ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
		<p>效果：只需要定义BeanClassTypeAutoProxyCreator，把需要代理的类型BaseService作为classTypes 的值。这样任何实现了BaseService接口的类都自动获得代理。使得程序员就像配置普通bean一样去配置一个需要事务代理的bean。使得程序员只需要去关心业务逻辑。而无需要去关注事务这些框架应该支持的事情。特别是当开发团队成员水平不一，或团队人员流动性大时， BeanClassTypeAutoProxyCreator就发挥了它的作用。一个好的架构设计应该对事务控制，异常处理，日志记录这些方面进行统一的规划和处理，才能保证系统的健壮性。<br />采用Spring框架进行项目开发，我们在获得它的IOC等好处，同时给我们增加了维护太多配置文件的负担。应该尽量减少bean的定义，更多采用嵌套bean定义。否则将加大项目后期的维护成本。作为一个架构设计者更是应该把通用性比较强的方面进行统一规划。</p>
<img src ="http://www.blogjava.net/Aisce/aggbug/142810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Aisce/" target="_blank">Aisce</a> 2007-09-05 10:09 <a href="http://www.blogjava.net/Aisce/articles/142810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring XML配置十二个最佳实践</title><link>http://www.blogjava.net/Aisce/articles/142771.html</link><dc:creator>Aisce</dc:creator><author>Aisce</author><pubDate>Tue, 04 Sep 2007 14:29:00 GMT</pubDate><guid>http://www.blogjava.net/Aisce/articles/142771.html</guid><wfw:comment>http://www.blogjava.net/Aisce/comments/142771.html</wfw:comment><comments>http://www.blogjava.net/Aisce/articles/142771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Aisce/comments/commentRss/142771.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Aisce/services/trackbacks/142771.html</trackback:ping><description><![CDATA[
		<p>Spring是一个强大的JAVA应用框架，广泛地应用于JAVA的应用程序。为Plain Old Java Objects（POJOs）提供企业级服务。Spring利用依赖注入机制来简化工作，同时提高易测性。Spring beans及依赖，以及beans类所需的服务都在配置文件中进行了详细的说明，这个配置文件是典型的XML格式。但是它既冗长又不实用。对于需要定义大量Spring beans的大工程来说，我们难以阅读和管理它。</p>
		<p>版权声明：任何获得Matrix授权的网站，转载时请务必保留以下作者信息和链接<br />作者:Jason;Li;evenbetter(作者的blog:http://blog.matrix.org.cn/page/evenbetter)<br />原文:http://www.onjava.com/pub/a/onjava/2006/01/25/spring-xml-configuration-best-practices.html<br />译文:http://www.matrix.org.cn/resource/article/44/44236_Spring+XML+Configurations.html<br />关键字:Spring;XML;Configurations</p>
		<p>在这篇文章里，对于Spring XML的配置，我将向你展示12种比较好的实践。其中的一些实践不仅是好的实践，更是必要的实践。除此以外，还有其他因素，例如领域模型的设计，都能影响XML的配置，但是这篇文章重点研究XML配置的易读性和易管理性。</p>
		<p>
				<font color="#000000">1.不要使用autowiring</font>
		</p>
		<p>       Spring可以通过类的自省来自动绑定其依赖部分，使得你不必明确指明bean的属性和构造器。Bean的属性可以通过属性名称或类型匹配来实现自动绑定。构造器通过类型匹配来实现自动绑定。你甚至可以指定自动检测自动绑定模式，它可以引导Spring选择一种适当的运行机制。先来看看下面的一个例子：</p>
		<p>    <font color="#009900">&lt;bean id="orderService"   class="com.Aisce.spring.OrderService"  autowire="byName"/&gt;</font><br /><br />      OrderService类的属性名在容器中用于匹配bean实例。自动绑定可以潜在地节省一些打字和减少一些混乱。但是在现实世界的工程里你不应该使用这种方式，这是因为它牺牲了配置的清晰性和可维护性。许多指南和介绍中大量吹捧自动绑定是Spring的一种极好的特征而没有提到这一特性所带来的牺牲。依我的观点，这就像Spring中的object－pooling，它更像是一种为了占据更多市场的商业特征。它对于XML配置文件的小巧化是一个好办法，但实际上也增加了复杂程度，尤其当你运行有大量类声明的工程时。虽然Spring允许你混合自动绑定和手动绑定，但是这个矛盾会使XML配置更加晦涩难懂。</p>
		<p>2.使用通俗的命名</p>
		<p>      这个方式对于Java编码也一样适用。在工程中使用清晰的、描述性的、协调的通俗名称对于开发者理解XML配置是十分有益的。例如对于bean ID，你可以根据通俗的Java类名来命名它。对于例子中OrderServiceDAO的bean ID命名为orderServiceDAO。对于大的工程，你可以在bean ID前面加上包名作为前缀。</p>
		<p>3. 使用简洁的形式</p>
		<p>简洁形式避免了冗长，是因为它从子元素中将属性值和参考写到属性中。例如下面的例子：</p>
		<p>    &lt;bean id="orderService" class="com.Aisce.spring.OrderService"&gt;<br />            &lt;property name="companyName"&gt; <br />                     &lt;value&gt;Aisce&lt;/value&gt; <br />            &lt;/property&gt; <br />            &lt;constructor-arg&gt;<br />                  &lt;ref bean="orderDAO"&gt;<br />            &lt;/constructor-arg&gt;<br />   &lt;bean&gt;<br /><br />可以使用简洁形式将上述代码重写为：</p>
		<p>    <font color="#339900">&lt;bean id="orderService" class="com.Aisce.spring.OrderService"&gt;<br />         &lt;property name="companyName"  value="Aisce"/&gt;<br />         &lt;constructor-arg ref="orderDAO"/&gt;<br />   &lt;/bean&gt;<br /></font><br />简洁形式功能在1.2版本中可以使用。对于&lt;ref local="..."&gt;没有简洁形式。<br />简洁形式不但可以节约你的打字，而且可以使XML配置文件清晰。它最引人注目的是当在一个配置文件中有大量定义的类时可以提高易读性。</p>
		<p>4. 对于构造器参数匹配，类型名比序号好。</p>
		<p>当一个构造器含有一个以上的同种类型的参数，或者属性值的标签已经被占用时，Spring允许你使用从0计数的序号来解决这些会带来混淆的问题。例如：</p>
		<p>    &lt;bean id="billingService"  class="com.Aisce.spring.BillingService"&gt; <br />         &lt;constructor-arg index="0" value="Aisce"/&gt; <br />         &lt;constructor-arg index="1" value="100"/&gt; <br />    &lt;/bean&gt;<br /><br />像下面这样，利用类型属性来编写会更好一些：</p>
		<p>    <font color="#009900">&lt;bean id="billingService"  class="com.Aisce.spring.BillingService"&gt; <br />         &lt;constructor-arg type="java.lang.String"  value="Aisce"/&gt;<br />         &lt;constructor-arg type="int" value="100"/&gt; <br />   &lt;/bean&gt;</font></p>
		<p>
				<br />使用索引可以稍稍减少一些冗长，但是和使用类型属性相比，它还是有容易发生错误的倾向和难于阅读的缺点。你应该只在构造器参数不明确的时候，才使用索引这一方法。</p>
		<p>5. 尽可能重用已定义过的bean</p>
		<p>Spring提供一种类似继承一样的机制来减少配置信息的复制并简化XML配置。定义一个子类可以从它父类那里继承配置信息，而父类实质上作为子类的一个模板。这就是大工程中所谓的重用。你所需要做的就是在父类bean中设置abstract=true，然后在子bean注明它自己的父类bean。例如：</p>
		<p>    <font color="#009900">&lt;bean id="abstractService" abstract="true"  class="com.Aisce.spring.AbstractService"&gt;<br />         &lt;property name="companyName"  value="Aisce"/&gt;<br />   &lt;/bean&gt; <br />   &lt;bean id="shippingService"  parent="abstractService" class="com.Aisce.spring.ShippingService"&gt;<br />         &lt;property name="shippedBy" value="Aisce"/&gt; <br />   &lt;/bean&gt;</font></p>
		<p>ShippingService类从abstractService类那里继承companyName属性的值--<font color="#009900">Aisce</font>。如果你没有为一个bean指明类或factory方法，那么这个bean便是抽象的。</p>
		<p>6. 尽量使用ApplicationContext来装配定义的bean</p>
		<p>像在Ant脚本中的引用一样，Spring的引用对于装配模块化的bean来说是很有用的。例如：</p>
		<p>    <font color="#009900">&lt;beans&gt;<br />         &lt;import  resource="billingServices.xml"/&gt;<br />         &lt;import  resource="shippingServices.xml"/&gt;<br />         &lt;bean id="orderService" class="com.Aisce.spring.OrderService"/&gt;<br />   &lt;beans&gt;<br /></font><br />相对于使用import在XML配置中来预装配，通过ApplicationContext来配置这些beans，显得更加灵活。利用ApplicationContext也使得XML配置易于管理。你可以像下面的例子那样在ApplictionContext构造器里布置bean：</p>
		<p>    <font color="#009900">String[] serviceResources = {"orderServices.xml", "billingServices.xml", "shippingServices.xml"}; <br />    ApplicationContext  orderServiceContext = new ClassPathXmlApplicationContext(serviceResources);<br /></font><br />7. 利用id作为bean的标识符</p>
		<p>你可以指定一个id或名称来作为bean的标识符。虽然使用id不会提高易读性，但是它可以让XML parser对bean的引用有效方面进行更好的验证。如果由于XML IDREF的限制而不能使用某个id，你可以利用names来作为bean的标识符。XML IDREF的限制是id必须以字母开头（或者在XML规范中定义的标点符号），后面接着字母，数字，连字号，下划线，冒号等。实际上，遇到XML IDREF限制的问题是很少见的。</p>
		<p>8. 在开发阶段使用依赖检验</p>
		<p>你可以在bean中给依赖检验的属性设置值，而不采用原先默认的空值，属性设置例如simple，object或all，以便容器进行依赖检验。当bean的全部的属性（或某类属性）需要被明确设置或自动绑定时，依赖检验便显得很有用。</p>
		<p>    <font color="#009900">&lt;bean id="orderService"  class="com.Aisce.spring.OrderService" dependency-check="objects"&gt; <br />         &lt;property name="companyName"  value="Aisce"/&gt; <br />         &lt;constructor-arg ref="orderDAO"/&gt;<br />   &lt;/bean&gt;<br /></font><br />在这个例子里，容器确保为orderService bean设置的属性不是primitives 或者 collections。为所有的bean设置默认依赖检测也是可以的，但是我们很少这样做，是因为有些bean的属性根本就不必设置。</p>
		<p>9. 为每个配置文件加上一个header comment</p>
		<p>最好使用descriptive id和名称来代替在XML配置文件中的注释。此外，加上一个配置文件header也很有用处，它可以概述文件中所定义的bean。你可以选择将描述内容加入description标签中。例如：</p>
		<p>    &lt;beans&gt;        <br />         &lt;description&gt; This is a Bean description.  &lt;/description&gt; <br />    &lt;/beans&gt;</p>
		<p>使用description标签的一个好处是可以容易地利用工具从标签中选取出description（的内容）。</p>
		<p>10. 对于任何变化，要与队友积极交流<br />当你重构Java代码时，你需要随时更新配置文件并且通知队友。XML配置文件也是代码，它们是应用程序的至关重要的部分，但是它们难于阅读和维护。大部分时间你既要阅读XML配置文件又要阅读运行中的Java代码。</p>
		<p>11. Setter injection优于constructor injection</p>
		<p>Spring提供3种类型的依赖注入： constructor injection,setter injection, 和method injection。我们一般只用前两种类型。</p>
		<p>    <font color="#009900">&lt;bean id="orderService"  class="com.Aisce.spring.OrderService"&gt;   <br />                &lt;constructor-arg ref="orderDAO"/&gt; <br />   &lt;/bean&gt; <br />   &lt;bean id="billingService"   class="com.Aisce.spring.BillingService"&gt;        <br />                &lt;property name="billingDAO"  ref="billingDAO"&gt;<br />   &lt;/bean&gt;<br /></font><br />这个例子中，orderService类使用的是constructor injection，而BillingService类使用的是setter injection。constructor injection可以确保bean不会在一个非法状态下被创建，但是setter injection更加灵活并且更易管理，尤其当类存在很多属性并且其中一些是可选的情况下。</p>
		<p>12. 不要滥用依赖注入</p>
		<p>作为最后一点，Spring ApplicationContext可以替你创建Java对象，但是并不是所有的Java对象都通过依赖注入来创建的。例如，全局的对象不应该通过ApplicationContext来创建。Spring是一个很棒的框架，但是，就易读性和易管理性而言，当定义大量bean的时候，基于XML的配置问题就会突出。过度的依赖注入会使XML配置变得复杂而且臃肿。记住！使用强大的IDE时，例如Eclipse和IntelliJ，与XML文件相比，Java代码更加易读，易维护，易管理。</p>
		<p>总结<br />对于Spring的配置，XML是很优秀的方式。但当定义大量bean时，基于XML配置会变得冗长，笨拙。Spring提供了丰富的配置选项。适当地利用其中的选项可以使XML配置清晰，但是，有些选项，例如autowiring（自动绑定），往往会降低易读性和易维护性。文章中所列举的实例，可以帮助你创建出清晰易读的XML配置文件。</p>
		<p>关于作者：<br />Jason Zhicheng Li是Object Computing, Inc. in St. Louis, MO（公司）一名资深的软件工程师。<br /></p>
<img src ="http://www.blogjava.net/Aisce/aggbug/142771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Aisce/" target="_blank">Aisce</a> 2007-09-04 22:29 <a href="http://www.blogjava.net/Aisce/articles/142771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>