2010年3月15日
#
在Java的世界里,無論類還是各種數(shù)據(jù),其結構的處理是整個程序的邏輯以及性能的關鍵。由于本人接觸了一個有關性能與邏輯同時并存的問題,于是就開始研究這方面的問題。找遍了大大小小的論壇,也把《Java 虛擬機規(guī)范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一氣之下把JDK的 src 解壓出來研究,擴然開朗,遂寫此文,跟大家分享感受和順便驗證我理解還有沒有漏洞。 這里就拿HashMap來研究吧。
HashMap可謂JDK的一大實用工具,把各個Object映射起來,實現(xiàn)了“鍵--值”對應的快速存取。但實際里面做了些什么呢?
在這之前,先介紹一下負載因子和容量的屬性。大家都知道其實一個 HashMap 的實際容量就 因子*容量,其默認值是 16×0.75=12; 這個很重要,對效率很一定影響!當存入HashMap的對象超過這個容量時,HashMap 就會重新構造存取表。這就是一個大問題,我后面慢慢介紹,反正,如果你已經知道你大概要存放多少個對象,最好設為該實際容量的能接受的數(shù)字。
兩個關鍵的方法,put和get:
先有這樣一個概念,HashMap是聲明了 Map,Cloneable, Serializable 接口,和繼承了 AbstractMap 類,里面的 Iterator 其實主要都是其內部類HashIterator 和其他幾個 iterator 類實現(xiàn),當然還有一個很重要的繼承了Map.Entry 的 Entry 內部類,由于大家都有源代碼,大家有興趣可以看看這部分,我主要想說明的是 Entry 內部類。它包含了hash,value,key 和next 這四個屬性,很重要。put的源碼如下
public Object put(Object key, Object value) {
Object k = maskNull(key);
這個就是判斷鍵值是否為空,并不很深奧,其實如果為空,它會返回一個static Object 作為鍵值,這就是為什么HashMap允許空鍵值的原因。
int hash = hash(k);
int i = indexFor(hash, table.length);
這連續(xù)的兩步就是 HashMap 最牛的地方!研究完我都汗顏了,其中 hash 就是通過 key 這個Object的 hashcode 進行 hash,然后通過 indexFor 獲得在Object table的索引值。
table???不要驚訝,其實HashMap也神不到哪里去,它就是用 table 來放的。最牛的就是用 hash 能正確的返回索引。其中的hash算法,我跟JDK的作者 Doug 聯(lián)系過,他建議我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他這樣一提,我就更加急了,可惜口袋空空啊!!!
不知道大家有沒有留意 put 其實是一個有返回的方法,它會把相同鍵值的 put 覆蓋掉并返回舊的值!如下方法徹底說明了 HashMap 的結構,其實就是一個表加上在相應位置的Entry的鏈表:
for (Entry e = table[i]; e != null; e = e.next) {
if (e.hash == hash && eq(k, e.key)) {
Object oldvalue = e.value;
e.value = value; //把新的值賦予給對應鍵值。
e.recordAccess(this); //空方法,留待實現(xiàn)
return oldvalue; //返回相同鍵值的對應的舊的值。
}
}
modCount++; //結構性更改的次數(shù)
addEntry(hash, k, value, i); //添加新元素,關鍵所在!
return null; //沒有相同的鍵值返回
}
我們把關鍵的方法拿出來分析:
void addEntry(int hash, Object key, Object value, int bucketIndex) {
table[bucketIndex] = new Entry(hash, key, value, table[bucketIndex]);
因為 hash 的算法有可能令不同的鍵值有相同的hash碼并有相同的table索引,如:key=“33”和key=Object g的hash都是-8901334,那它經過indexfor之后的索引一定都為i,這樣在new的時候這個Entry的next就會指向這個原本的table[i],再有下一個也如此,形成一個鏈表,和put的循環(huán)對定e.next獲得舊的值。到這里,HashMap的結構,大家也十分明白了吧?
if (size++ >= threshold) //這個threshold就是能實際容納的量
resize(2 * table.length); //超出這個容量就會將Object table重構
所謂的重構也不神,就是建一個兩倍大的table(我在別的論壇上看到有人說是兩倍加1,把我騙了),然后再一個個indexfor進去!注意!!這就是效率!!如果你能讓你的HashMap不需要重構那么多次,效率會大大提高!
說到這里也差不多了,get比put簡單得多,大家,了解put,get也差不了多少了。對于collections我是認為,它是適合廣泛的,當不完全適合特有的,如果大家的程序需要特殊的用途,自己寫吧,其實很簡單。(作者是這樣跟我說的,他還建議我用LinkedHashMap,我看了源碼以后發(fā)現(xiàn),LinkHashMap其實就是繼承HashMap的,然后override相應的方法,有興趣的同人,自己looklook)建個 Object table,寫相應的算法,就ok啦。
舉個例子吧,像 Vector,list 啊什么的其實都很簡單,最多就多了的同步的聲明,其實如果要實現(xiàn)像Vector那種,插入,刪除不多的,可以用一個Object table來實現(xiàn),按索引存取,添加等。
如果插入,刪除比較多的,可以建兩個Object table,然后每個元素用含有next結構的,一個table,如果要插入到i,但是i已經有元素,用next連起來,然后size++,并在另一個table記錄其位置
HashMap用法
package hashmap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class HashMap1 {
//初始化
private void init(Map map,String kind)
{
if(map != null)
{
for(int i=1; i<6; i++)
{
map.put(String.valueOf(i),kind+i);
}
}
}
//結果輸出
private void outPut(Map map)
{
if(map != null)
{
Object key = null;
Object value = null;
Iterator iterater = map.keySet().iterator();
while(iterater.hasNext())
{
key = iterater.next();
value = map.get(key);
System.out.print(key+": "+value+"\t");
}
System.out.println("\n");
}
}
public static void main(String args[])
{
HashMap hashmap = new HashMap();
hashmap.put("x", "1");
hashmap.put("u", "2");
hashmap.put("z", "3");
hashmap.put("h", "4");
hashmap.put("a", "5");
hashmap.put("o", "6");
hashmap.put("g", "7");
hashmap.put("u", "8");
hashmap.put("a", "9");
hashmap.put("n", "10");
hashmap.put("g", "11");
Object key = null;
Object value = null;
Iterator iterater = hashmap.keySet().iterator();
while(iterater.hasNext())
{
key = iterater.next();
value = hashmap.get(key);
System.out.print(key+": "+value+"\t");
}
System.out.println("\n");
}
//聲明HashMap對象
private void setHashMap()
{
HashMap hashMap = new HashMap();
init(hashMap,"HashMap");
hashMap.put(null,"鍵值為空");
hashMap.put("值為空",null);
System.out.println("這是HashMap對象的鍵與值:");
outPut(hashMap);
}
//聲明Hashtable對象
private void setHashtable(){
Hashtable hashtable = new Hashtable();
init(hashtable,"Hashtable");
//hashtable.put(null,"鍵值為空"); Hashtable不允許鍵或值為null;
//hashtable.put("值為空",null);
System.out.println("這是Hashtable對象的鍵與值:");
outPut(hashtable);
}
//聲明LinkedHashMap對象
private void setLinkedHashMap(){
LinkedHashMap linkedHashMap = new LinkedHashMap();
init(linkedHashMap,"LinkedHashMap");
linkedHashMap.put(null,"鍵值為空");
linkedHashMap.put("值為空",null);
System.out.println("這是LinkedHashMap對象的鍵與值:");
outPut(linkedHashMap);
}
//聲明TreeMap對象
private void setTreeMap(){
TreeMap treeMap = new TreeMap();
//TreeMap treeMap = new TreeMap(new MySort());//按自定義的方式排序
init(treeMap,"TreeMap");
treeMap.put("0", "后插入的值");
//treeMap.put(null,"鍵值為空"); TreeMap不允許鍵或值為null
//treeMap.put("值為空",null);
System.out.println("這是TreeMap對象的鍵與值:");
outPut(treeMap);
}
// public static void main(String[] args){
// HashMapDemo tm = new HashMapDemo();
// tm.setHashMap();
// tm.setHashtable();
// tm.setLinkedHashMap();
// tm.setTreeMap();
//
// Map hashMap = new HashMap();
// hashMap.put(null, "鍵值為null");
// hashMap.put("值為null", null);
// System.out.println("新建HashMap對象元素的記錄數(shù)是:"+hashMap.size());
// hashMap.remove(null);
// System.out.println("刪除鍵值為null的HashMap對象元素的記錄數(shù)是:"+hashMap.size());
// }
第一種:
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
效率高,以后一定要使用此種方式!
第二種:
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
效率低,以后盡量少使用!
HashMap的遍歷有兩種常用的方法,那就是使用keyset及entryset來進行遍歷,但兩者的遍歷速度是有差別的,下面請看實例: |
import java.util.*;
public class HashMapTest {
public static void main(String[] args) {
HashMap< Integer,String> hashmap = new HashMap< Integer,String>();
for (int i = 0; i <1000; i++ ) {
hashmap.put(i, "thanks");
}
long bs = Calendar.getInstance().getTimeInMillis();
Iterator iterator = hashmap.keySet().iterator();
while (iterator.hasNext()) {
System.out.print(hashmap.get(iterator.next()));
}
System.out.println();
System.out.println(Calendar.getInstance().getTimeInMillis() - bs);
listHashMap();
}
public static void listHashMap() {
java.util.HashMap< Integer,String> hashmap = new java.util.HashMap< Integer,String>();
for (int i = 0; i < 1000; i++ ) {
hashmap.put(i, "thanks");
}
long bs = Calendar.getInstance().getTimeInMillis();
Iterator< Map.Entry< Integer,String>> it = hashmap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry< Integer,String> entry = it.next();
// entry.getKey() 返回與此項對應的鍵
// entry.getValue() 返回與此項對應的值
System.out.print(entry.getValue());
}
System.out.println();
System.out.println(Calendar.getInstance().getTimeInMillis() - bs);
}
對于keySet其實是遍歷了2次,一次是轉為iterator,一次就從hashmap中取出key所對于的value。而entryset只是遍歷了第一次,他把key和value都放到了entry中,所以就快了。
注:Hashtable的遍歷方法和以上的差不多!
|
web.xml
// 這里不需要配置字符過濾,網上有的例子加了,實際上
webwork.properties里設置如下就可以了頁面也是GBK
webwork.locale=zh_CN
webwork.i18n.encoding=GBK
---------------------------
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" " http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.atlassian.xwork.ext.ResolverSetupServletContextListener</listener-class>
</listener>
<!--
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->
<servlet>
<servlet-name>webwork</servlet-name>
<servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>com.opensymphony.webwork.views.freemarker.FreemarkerServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>webwork</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>webwork</taglib-uri>
<taglib-location>/WEB-INF/webwork.tld</taglib-location>
</taglib>
</web-app>
---------------------------
xwork.xml
==================---------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">
<xwork>
<include file="webwork-default.xml"/>
<package name="users" extends="webwork-default"
externalReferenceResolver="com.atlassian.xwork.ext.SpringServletContextReferenceResolver">
<interceptors>
<interceptor name="reference-resolver" class="com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor"/>
<interceptor-stack name="myDefaultWebStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="reference-resolver"/>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="params"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myDefaultWebStack"/>
<action name="blogUser" class="com.jsblog.action.BlogUserAction">
<external-ref name="baseDao">baseDaoTarget</external-ref> //這里是把applicationContext里配置的DAO 注入action里 action里要有baseDao屬性
<result name="success">/add.htm</result>
</action>
-------------------------------------------------------------------------
applicationContext.xml
---------------------------------------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="no" default-dependency-check="none" default-lazy-init="false">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
</property>
<property name="url">
<value>jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=jsblog;SelectMethod=cursor</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value>jfy</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="mappingResources">
<list>
<value>com/jsblog/BlogUserForm.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
net.sf.hibernate.dialect.SQLServerDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<bean id="baseDaoTarget" class="com.jsblog.dao.BlogUserDao">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
</beans>
---------------------------------------------------------------------------
BlogUserDao.java
---------------------------------------------------------------------------
package com.jsblog.dao;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.SessionFactoryUtils;
import com.jsblog.BlogUserForm;
import java.io.Serializable;
import java.util.List;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
public class BlogUserDao extends HibernateDaoSupport implements BaseDao {
public void insert(BlogUserForm bloguser) {
getHibernateTemplate().save(bloguser);
}
}
基于webwork spring hibernate 項目的開發(fā)
這三者的結合,應該是java web編程最好的模式。
首先說明三者各自負責的職務:
1 hibernate 負責數(shù)據(jù)庫的操作
2 spring 負責真正的業(yè)務操作
3 webwork 負責請求轉交,并把spring的處理結果返回給用戶
以往的開發(fā)中,很多人注重MVC模式。的確,這種模式把程序以面向對象的思想分成 了三個部分。但在web開發(fā)中,并不能單純的運用此種模式:web開發(fā)的View是固定的(頁面),而在引入hibernate后,model這一塊也非常簡單和清晰。就剩下control了,這是web開發(fā)的關鍵部分,現(xiàn)在流行的做法便是將control細分成兩個部分:dispacher(轉交器)和business object(處理業(yè)務邏輯的對象)。并將后者抽出接口,甚至和model共享接口,一邊真正做到對dispacher隱藏邏輯實現(xiàn)。
而這種M-V-D-B(model-view-dispacher-business object)模式的實現(xiàn)有好多方式。比如一個bo(business object)對象的創(chuàng)建,你可以直接 new,也可以動態(tài)加載,采用工廠方法,抽象工廠。但最好的就是用spring容器。dispacher只管用接口就行了,具體類已經有spring的 AOP給注入了。
當然spring也可以很好地和hibernate結合,你可以采用DAO,也可以用spring的hibernate 模板。但這都不重要,因為你的業(yè)務對象已經和調用層徹底分開了,當業(yè)務層需要和hibernate打交道的時候,直接做個HibernateUtil也未嘗不可呀。怎么做都已經不是關鍵。
下面就具體介紹spring webwork的結合方式。
在webwork 中的wiki doc中有三種結合方式(google查),我這里采用的最后一種--采用一個自動裝配的攔截器com.opensymphony.xwork.spring.interceptor.ActionAutowiringInterceptor關鍵代碼如下:
ApplicationContext applicationContext = (ApplicationContext)ActionContext.getContext().getApplication().get(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
factory = new SpringObjectFactory();
factory.setApplicationContext(getApplicationContext());
Action bean = invocation.getAction();
factory.autoWireBean(bean);
ActionContext.getContext().put(APPLICATION_CONTEXT, context);
1、webwork、spring的集成
(1)、開啟spring的集成:
首先將最新的spring的jar加到classpath中,然后在src目錄下建立webwork.properties文件,文件只包含下面的內容
webwork.objectFactory=spring
這種情況下,所有的對象都至少會試圖使用Spring來創(chuàng)建.如果它們不能被Spring創(chuàng)建,然后WebWork會自己創(chuàng)建對象.接下來,在
web.xml打開Spring的Listener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
由于使用標準的Listener來集成Spring,它可以被配置來支持除了applicationContext.xml之外的配置文件.把下面的幾行添加到
web.xml會讓Spring的ApplicationContext從所有匹配給定的規(guī)則的文件中初始化:
<!-- Context Configuration locations for Spring XML files -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext
</context-param>
根據(jù)需要配置相應的spring上下文文。
(2)、在spring中初始化Action
正常情況下,在xwork.xml里可以為每個action指定類.當你使用SpringObjectFactory時WebWork會請求Spring來
創(chuàng)建action并按照缺省指定的自動裝配行為來裝配依賴的組件.SpringObjectFactory 也會設置所有的bean的后置處理程序
(post processors)來完成類似對Action進行事務,安全等等方面的代理的事情.Spring可以不依賴外在的配置來自動確定.
對于大多數(shù)的使用,這就是全部需要的了,用來配置action,設置它們獲取服務和依賴組件.
強烈推薦使用一種聲明式的方法來讓Spring知道為action提供什么.這包括讓bean能夠自動裝配,無論是把Action里的
依賴的屬性命名為和Spring應該提供的Bean的名字一致(這允許基于名字的自動裝配),或者使用by type方式的自動裝配,也就是在注冊到
Spring的Bean中需要的類型僅擁有一個.也可以包括使用JDK5的標準來聲明事務和安全需求,而不是必須在你的Spring配置里明確設置代理.
如果能找到方法讓Spring在沒有任何明確的配置(在_applicationContext.xml_中)的情況下知道需要為action做什么,那么就不
需要在兩個地方維護這個配置了.
當然,有時候可能想要Spring完全來管理bean.這是有實際意義的,例如,如果想要為bean設置更復雜的AOP或者Spring相關的技術,
例如Acegi.為了達到這個目的,所有必須要做的事情就是在Spring的 applicationContext.xml 里配置bean,然后在 xwork.xml
里改變你的WebWork action的類屬性來使用在Spring里面定義的bean的名字,而不再使用類名.
xwork.xml文件也會改變action類的屬性,最后留下的就像這樣
<xwork>
<!-- Include webwork defaults (from WebWork JAR). -->
<include file="webwork-default.xml" />
<!-- Configuration for the default package. -->
<package name="default" extends="webwork-default">
<action name="register" class="userAction" method="register">
<result name="success">/pages/registerSuccess.jsp</result>
</action>
</package>
</xwork>
在applicationContext.xml 里定義了一個名字為 "userAction"的Spring的bean.注意cn.com.nawang.Action.UserAction不需要
改變,因為它可能是自動裝配的:
<bean id="userAction" class="cn.com.nawang.action.UserAction" >
<property name="userService" ref="userService"/>
</bean>
注:bean中的id值必須與xwork.xml中對應的class值一致。
2、 基于Hibernate3的原生API實現(xiàn)DAO
Hibernate 3.0.1引入了一個新的特性:“帶上下文環(huán)境的Session”。 這一特性使得Hibernate自身具備了每個事務綁定當前 Session 對象的功能。
這與Spring中每個Hibernate的 Session 與事務同步的功能大致相同。
(1)、 為Dao創(chuàng)建基類BaseDao
public class BaseDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession(){
Session session = this.sessionFactory.getCurrentSession();
return session;
}
}
(2)、在子類Dao中實現(xiàn)具體持久化操作
public class UserDao extends BaseDao implements IUserDao {
public void saveUser(User user) throws HibernateException {
getSession().save(user);
}
}
(3)、在上下文中配置
<bean id="baseDao" class="cn.com.nawang.dao.BaseDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDao" class="cn.com.nawang.dao.impl.UserDao" parent="baseDao"/>
<bean id="userService" class="cn.com.nawang.service.impl.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userAction" class="cn.com.nawang.action.UserAction" >
<property name="userService" ref="userService"/>
</bean>
重啟服務,在web頁面上觸發(fā)register的action,執(zhí)行后,拋出下面的異常:
Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
google了下,大概明白了是因為沒有配置了事務導致的錯誤。在配置事務之前,查看了以前的一個采用HibernateDaoSupport實現(xiàn)的項目,記得
當時并不需要配置事務就可以正常運行。于是,讓UserDao繼承于HibernateDaoSupport,修改后的代碼如下:
public class UserDao extends BaseDao implements IUserDao {
public void saveUser(User user) throws HibernateException {
getHibernateTemplate().save(user);
}
}
接下去,修改spring上下文中的相關配置,
<!--
<bean id="baseDao" class="cn.com.nawang.dao.BaseDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>-->
<bean id="userDao" class="cn.com.nawang.dao.impl.UserDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userService" class="cn.com.nawang.service.impl.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userAction" class="cn.com.nawang.action.UserAction" >
<property name="userService" ref="userService"/>
</bean>
保存修改后的,重啟服務,再次觸發(fā)register的action,用戶信息成功保存。
去掉HibernateDaoSupport的dao實現(xiàn)后,又換回基于hibernate3.0原生API的實現(xiàn)方式,根據(jù)之前google后的結果,給userService配置
事務,拷貝了下之前項目中的配置,并做相應修改,修改后的內容如下:
<bean id="baseTransaction"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="proxyTargetClass" value="true"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="baseDao" class="cn.com.nawang.dao.BaseDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDao" class="cn.com.nawang.dao.impl.UserDao" parent="baseDao"/>
<bean id="userServiceTarget" class="cn.com.nawang.service.impl.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userService" parent="baseTransaction">
<property name="target" ref="userServiceTarget"/>
</bean>
<bean id="userAction" class="cn.com.nawang.action.UserAction" >
<property name="userService" ref="userService"/>
</bean>
保存修改內容,重啟服務,重啟中出現(xiàn)錯誤,查看了spring in action中的相關配置,發(fā)現(xiàn)baseTransaction這個bean的配置稍有不同,
上面那個配置是參考springside的,當時那個項目趕,就直接拿過來用,也沒出現(xiàn)問題,就不認真去考慮,現(xiàn)在拷貝到現(xiàn)有項目中,卻出錯了,
于是先根據(jù)書上的介紹做相應修改,改后的內容如下:
<bean id="baseTransaction"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
去掉了<property name="proxyTargetClass" value="true"/>的配置,將abstract="true"改為lazy-init="true",保存修改
重啟服務,并再次觸發(fā)register的action,一切如所愿。
|