相信spring現(xiàn)在已經(jīng)成為j2ee開發(fā)的首選框架,也深受廣大java開發(fā)者的喜愛,它的ioc、aop以及各種擴展應(yīng)用都使開發(fā)者受益。它不僅是一個開發(fā)框架,同時還把很多優(yōu)秀的設(shè)計理念潛移默化的傳遞給了使用者...好了,具體spring有多優(yōu)秀不是這篇文章的重點,以下就談一下筆者在項目中使用spring的實際經(jīng)驗吧。 1 項目的哪些地方需要用到spring 這應(yīng)該是一個相當大的話題,不過還是有必要闡述一下。就當前典型的j2ee應(yīng)用或web應(yīng)用上流行的mvc(如ssh)框架而言,spring應(yīng)用在以下幾個方面 核心開發(fā)框架:spring作為核心容器,通過主要組件BeanFactory并使用ioc實現(xiàn)對所有bean的管理。在實際應(yīng)用中,首先要秉承接口模式的編程思路,定義應(yīng)用類之前先定義接口,然后再定義實現(xiàn)類,而調(diào)用的時候則調(diào)用接口而不是實現(xiàn)類。同時需要配置一個或多個spring的xml配置文件,把調(diào)用接口映射到實現(xiàn)類。 dao端的框架支持:在三層框架模式下(web,service,dao),通過HibernateTemplate和JdbcTemplate等支持類,在dao層對jdbc以及Hibernate等主流的ORM數(shù)據(jù)庫調(diào)用模式進行支持。一般都有專門的jdbc以及hibernate的配置文件對DAO層使用的bean進行設(shè)置。 service端的框架支持:在serivce層通過ioc進行bean的管理配置,同時進行事務(wù)控制的定義。 aop:利用攔截器配置管理特性 jndi:利用spring的context組件對jndi進行定義,通常用于數(shù)據(jù)庫連接池的配置和查找 其他:spring1.2版本的mvc組件是針對web端的應(yīng)用框架,盡管理念非常oop,不過實際使用的時候確實不如struts2好使,spring 2.0以后的mvc據(jù)說有很大改進,以后有機會再用吧。另外spring的定時任務(wù)(job)也經(jīng)常用到,后邊會有提及。 2 spring的orm組件的使用經(jīng)驗 ssh框架的一個典型應(yīng)用,通過HibernateTemplate實現(xiàn)spring與hibernate的集成。一般都是通過在配置文件向繼承HibernateDaoSupport的dao實現(xiàn)類注入sessionFactory,這個sessionFactory實現(xiàn)類一般被定義為LocalSessionFactoryBean,而LocalSessionFactoryBean這個類也屬于spring的hibernate支持包,它的一個重要屬性是dataSource,對應(yīng)的是jdbc的DataSource接口,而這個dataSource又可以通過ioc的方式注入實際的實現(xiàn)類,這個類既可以是各種java連接池的DataSource實現(xiàn)類,也可以是JndiObjectFactoryBean--spring用于進行數(shù)據(jù)源查找的jndi實現(xiàn)類。綜上所述,正式由于這一連串的聯(lián)系,實現(xiàn)了hibernate模式下的數(shù)據(jù)庫接入。而jdbc模式也是如此聯(lián)系,不同的是spring使用JdbcTemplate類進行支持。在使用中一些細節(jié)需要注意,比如 如何實現(xiàn)批量更新:HibernateTemplate的bulkUpdate方法可以用hql語句直接進行批量更新 對結(jié)果列表進行加工:不論通過jdbc還是hibernate方式,如果需要對find方法取得的列表中的對象進行加工,顯然使用回調(diào)模式進行效率更高。實際上如果使用HibernateTemplate并且希望查詢出的結(jié)果不是對象列表而是數(shù)組列表,那么也可以使用回調(diào),如下: String hql = "select t.id,t.name from test t"; List list = (List) this.getHibernateTemplate().execute( new HibernateCallback() { public Object doInHibernate(Session session) throws SQLException, HibernateException { SQLQuery query = session.createSQLQuery(sql); List children = query.list(); return children; } }); Iterator it = list.iterator(); while(it.hasNext()){ Object[] obj = (Object[])it.next(); System.out.println("id:" + obj[0]); //do some business here } 如上述代碼所示,某些時候我們希望直接使用字段來進行邏輯處理,那么HibernateTemplate的find方法顯然是不合適的,而回調(diào)模式返回的list中的內(nèi)容是對象數(shù)組 調(diào)用存儲過程:HibernateTemplate可以通過回調(diào)調(diào)用存儲過程 hibernateTemplate.execute(new HibernateCallback(){ public Object doInHibernate(Session session) throws SQLException{ CallableStatement cs = session.connection().prepareCall("{call usr.someProc}"); cs.executeUpdate(); return null; } } ); 3 spring的事務(wù)控制 在項目中,一般使用spring的聲明式方法控制數(shù)據(jù)庫事務(wù),定義數(shù)據(jù)庫事務(wù)只需要通過配置文件中配置即可,這種模式的技術(shù)基礎(chǔ)是基于AOP的。 事務(wù)配置定義:在三層構(gòu)架中,通常都在service層進行業(yè)務(wù)邏輯處理,以及事務(wù)控制。因此spring在service層可以單獨定義一個配置文件,映射service層中使用的bean,并且在定義這個bean的配置同時進行事務(wù)聲明,有多種方式。最直接的方式是定義這個bean的實現(xiàn)類為TransactionProxyFactoryBean--spring的事務(wù)控制代理,這種事務(wù)配置可以參見下面的代碼例子: <bean id="someBusinessBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="target"><ref bean="someBusinessBeanImpl"/></property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> 在上面的代碼中定義了someBusinessBean這個bean,其中target屬性中定義實際的業(yè)務(wù)接口實現(xiàn)類。并且在transactionAttributes屬性中針對method進行事務(wù)聲明,最常用的聲明是PROPAGATION_REQUIRED--支持當前事務(wù),如果當前沒有事務(wù),就新建一個事務(wù)。另外可以定義只讀事務(wù)readOnly,用于只讀的數(shù)據(jù)庫操作。同時我們還注意到事務(wù)定義中包含了異常情況的配置:如果出現(xiàn)MyCheckedException這個自定義異常,則數(shù)據(jù)庫進行回滾。 還有一種方式是繼承式事務(wù)定義,例子如下: <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop> <prop key="update*">PROPAGATION_REQUIRED,-MyCheckedException</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> <bean id="someBusinessBean" parent="txProxyTemplate"> <property name="target"> <bean class="com.myBusi.someBusinessBeanImpl"> <property name="dao" ref="dao"/> </bean> </property> </bean> 可以看出,這種方式先使用一個父類作為事務(wù)控制的統(tǒng)一定義,然后具體的業(yè)務(wù)bean通過繼承來實現(xiàn)事務(wù)的配置。其實這2中配置方式并沒有本質(zhì)的區(qū)別,只是第二種定義起來會省事一點。 另外在實際項目中有一個發(fā)現(xiàn),在websphere6.0的容器下部署的web應(yīng)用,使用websphere自帶的數(shù)據(jù)庫連接池,當spring事務(wù)配置為readOnly,在數(shù)據(jù)量比較大,并且有一定并發(fā)量時會導致websphere連接池拋出異常,并導致性能嚴重下降。去掉readOnly選項就恢復正常了,這種情況不容易在測試環(huán)境重現(xiàn),因此只能去掉readOnly選項,發(fā)現(xiàn)去掉以后性能也沒有太多的下降。 另外如果一些特殊的場景直接在代碼中進行事務(wù)提交(比如大批量插入數(shù)據(jù)),則需要用到spring的編程事務(wù),PlatformTransactionManager這個類是spring針對編程式事務(wù)的支持類。 4 spring與數(shù)據(jù)庫連接池 在spring中可以很方便的配置數(shù)據(jù)庫連接池,一種是直接配置連接池,以proxool連接池為例,配置代碼如下: <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="alias"><value>mydb</value></property> <property name="user"><value>test</value></property> <property name="password"><value>test</value></property> <property name="driver"><value>com.mysql.jdbc.Driver</value></property> <property name="driverUrl"><value>jdbcUrl</value></property> <property name="minimumConnectionCount"><value>10</value></property> <property name="maximumConnectionCount"><value>20</value></property> <property name="prototypeCount"><value>1</value></property> <property name="houseKeepingSleepTime"><value>90000</value></property> </bean> 如上,在配置文件中定義了dataSource這個bean,映射到ProxoolDataSource這個proxool的數(shù)據(jù)庫數(shù)據(jù)源的實現(xiàn)類,在屬性里的配置就是連接池的一些基本參數(shù) 我想更常用的還是使用jndi作為數(shù)據(jù)源,配置代碼如下: <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"><value>jdbc/mydblink</value></property> </bean> 在上面的代碼中使用JndiObjectFactoryBean作為數(shù)據(jù)源,而這個數(shù)據(jù)源實際負責實現(xiàn)jndi的查找,在容器中查找到j(luò)ndiName屬性定義的名稱所對應(yīng)的實際的數(shù)據(jù)源,來提供給應(yīng)用進行調(diào)用。實際的數(shù)據(jù)源則是在tomcat、weblogic、websphere等中間件容器中定義的。 5 其他的spring心得 直接獲得bean:有很多時候,我們不希望頻繁的修改配置文件以及增加set方法來得到spring容器定義的bean,那么可以使用ApplicationContext的getBean方法來直接獲取bean的實例。 job定義:spring支持定時計劃任務(wù),一種是一次性觸發(fā),更有用的一種的定時輪詢,寫法例子如下: "0 0/5 14-18 * * ?" 在每天下午2點下午6點期間的每5分鐘觸發(fā) OpenSessionInView:spring為了支持在頁面中延遲加載事務(wù)的一個filter,建議謹慎使用,容易對數(shù)據(jù)庫連接性能造成瓶頸 總結(jié):以上列舉了一些項目中使用spring的地方,相信還有更多的沒有列舉出來,在以后的文章里再補充吧 |
|