最近協助一些BEA客戶做調優,他們使用了Spring,出現了各種各樣的性能問題,這些問題其實都是不容易重現的,其中,我自己捕獲了一些ThreadDump,并report了給Spring JIRA。這個Case的情況是:Spring會偶然出現CPU 100%的情況,WebLogic Server崩潰,我后來分析了線程Dump,覺得是一種Lock Contention的情形,幸好,Juergen Hoeller很快給我Fixed了這個Bug:
http://jira.springframework.org/browse/SPR-4664
使用Java編程的同學都建議Review一下,呵呵:
這是2.5.4以前的代碼:
/**
*?Cache?of?TransactionAttributes,?keyed?by?DefaultCacheKey?(Method?+?target?Class).
*?<p>As?this?base?class?is?not?marked?Serializable,?the?cache?will?be?recreated
*?after?serialization?-?provided?that?the?concrete?subclass?is?Serializable.
*/
final
?Map?attributeCache?
=
?
new
?HashMap();
/**
*?Determine?the?transaction?attribute?for?this?method?invocation.
*?<p>Defaults?to?the?class's?transaction?attribute?if?no?method?attribute?is?found.
*?
@param
?method?the?method?for?the?current?invocation?(never?<code>null</code>)
*?
@param
?targetClass?the?target?class?for?this?invocation?(may?be?<code>null</code>)
*?
@return
?TransactionAttribute?for?this?method,?or?<code>null</code>?if?the?method
*?is?not?transactional
*/
public
?TransactionAttribute?getTransactionAttribute(Method?method,?Class?targetClass)?{
//
?First,?see?if?we?have?a?cached?value.
Object?cacheKey?
=
?getCacheKey(method,?targetClass);
synchronized
?(
this
.attributeCache)?{
Object?cached?
=
?
this
.attributeCache.get(cacheKey);
if
?(cached?
!=
?
null
)?{
//
?Value?will?either?be?canonical?value?indicating?there?is?no?transaction?attribute,
//
?or?an?actual?transaction?attribute.
if
?(cached?
==
?NULL_TRANSACTION_ATTRIBUTE)?{
return
?
null
;
}
else
?{
return
?(TransactionAttribute)?cached;
}
}
else
?{
//
?We?need?to?work?it?out.
TransactionAttribute?txAtt?
=
?computeTransactionAttribute(method,?targetClass);
//
?Put?it?in?the?cache.
if
?(txAtt?
==
?
null
)?{
this
.attributeCache.put(cacheKey,?NULL_TRANSACTION_ATTRIBUTE);
}
else
?{
if
?(logger.isDebugEnabled())?{
logger.debug(
"
Adding?transactional?method?[
"
?
+
?method.getName()?
+
?
"
]?with?attribute?[
"
?
+
?txAtt?
+
?
"
]
"
);
}
this
.attributeCache.put(cacheKey,?txAtt);
}
return
?txAtt;
}
}
}
這是2.5.4 Fixed后的代碼:
????
/**
?????*?Cache?of?TransactionAttributes,?keyed?by?DefaultCacheKey?(Method?+?target?Class).
?????*?<p>As?this?base?class?is?not?marked?Serializable,?the?cache?will?be?recreated
?????*?after?serialization?-?provided?that?the?concrete?subclass?is?Serializable.
?????
*/
????
final
?Map?attributeCache?
=
?CollectionFactory.createConcurrentMapIfPossible(
16
);
????
/**
?????*?Determine?the?transaction?attribute?for?this?method?invocation.
?????*?<p>Defaults?to?the?class's?transaction?attribute?if?no?method?attribute?is?found.
?????*?
@param
?method?the?method?for?the?current?invocation?(never?<code>null</code>)
?????*?
@param
?targetClass?the?target?class?for?this?invocation?(may?be?<code>null</code>)
?????*?
@return
?TransactionAttribute?for?this?method,?or?<code>null</code>?if?the?method
?????*?is?not?transactional
?????
*/
????
public
?TransactionAttribute?getTransactionAttribute(Method?method,?Class?targetClass)?{
????????
//
?First,?see?if?we?have?a?cached?value.
????????Object?cacheKey?
=
?getCacheKey(method,?targetClass);
????????Object?cached?
=
?
this
.attributeCache.get(cacheKey);
????????
if
?(cached?
!=
?
null
)?{
????????????
//
?Value?will?either?be?canonical?value?indicating?there?is?no?transaction?attribute,
????????????
//
?or?an?actual?transaction?attribute.
????????????
if
?(cached?
==
?NULL_TRANSACTION_ATTRIBUTE)?{
????????????????
return
?
null
;
????????????}
????????????
else
?{
????????????????
return
?(TransactionAttribute)?cached;
????????????}
????????}
????????
else
?{
????????????
//
?We?need?to?work?it?out.
????????????TransactionAttribute?txAtt?
=
?computeTransactionAttribute(method,?targetClass);
????????????
//
?Put?it?in?the?cache.
????????????
if
?(txAtt?
==
?
null
)?{
????????????????
this
.attributeCache.put(cacheKey,?NULL_TRANSACTION_ATTRIBUTE);
????????????}
????????????
else
?{
????????????????
if
?(logger.isDebugEnabled())?{
????????????????????logger.debug(
"
Adding?transactional?method?[
"
?
+
?method.getName()?
+
?
"
]?with?attribute?[
"
?
+
?txAtt?
+
?
"
]
"
);
????????????????}
????????????????
this
.attributeCache.put(cacheKey,?txAtt);
????????????}
????????????
return
?txAtt;
????????}
????}
但是2.5.4 snapshot是未經很好測試的版本,客戶一般不太敢用。
我不知道其實有多少客戶真正地把Spring投入到高并發性環境下使用,
如果有,他們應該會能碰到我所碰到的情形。