Spring In Action讀書筆記
第一章
1.Spring採用4種策略減少Java開發復雜度
基於POJO的輕量級和最小侵入性編程 依賴註入和面向接口實現松耦合 基於切面和慣例進行聲明式編程 通過切面和模板降低樣板式代碼
PS:POJO
POJO(Plain Ordinary Java Object)簡單的Java對象,實際就是普通JavaBeans,是為了避免和EJB混淆所創造的簡稱。
使用POJO名稱是為了避免和EJB混淆起來, 並且簡稱比較直接. 當中有一些屬性及其getter setter方法的類,沒有業務邏輯。有時能夠作為VO(value -object)或dto(Data
Transform Object)來使用.當然,假設你有一個簡單的運算屬性也是能夠的,但不同意有業務方法,也不能攜帶有connection之類的方法。
2.依賴註入的三種方式
1. 接口註入
2. Setter方法註入
3. 構造方法註入
詳細可參考:http://developer.51cto.com/art/201106/266978.htm
依賴註入:讓組件依賴於抽象,當組件要與其它實際對象發生依賴關系時。通過抽象來註入依賴的實際對象。
最大的優點是松耦合。
3.Spring最經常使用的三種應用上下文
1)ClassPathXmlApplicationContext:從classpath處獲取xml文件來載入一個上下文。
2)ClassPathXmlApplicationContext:從文件系統中獲取xml文件來載入一個上下文。
3)XmlWebApplicationContext:從web應用獲取xml文件來載入一個上下文。
這三個類都是ApplicationContext接口的實現。
使用:
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");//config.xml在src文件夾下
ApplicationContext context = new FileSystemXmlApplicationContext("d:/config.xml");
4.Bean的生命周期
傳統Java應用中的: new進行實例化,就能夠被使用,一旦不被使用,JVM自己主動回收Spring容器中的Bean:
實例化。填充屬性,(假設實現對應接口就)傳BeanID。傳BeanFactory容器實例,傳應用上下文的引用。調用postProcessBeforeInitialization(),調用afterpropertiesSet()。假設聲明了init-method,也調用該方法。調用postProcessAfterInitialization方法。 此時已經能夠被應用程序使用。將一直駐留在應用上下文中,直到該應用上下文被銷毀。 假設Bean實現了DisosableBean接口,調用destroy()接口方法,假設用destroy-method聲明了銷毀方法。就調用該方法。
第二章
1.兩種配置bean的方法
用一個或多個XML;基於Java註解2.factory-method
假設想聲明的bean沒有公開的構造方法,能夠在配置文件裏加factory-method指定返回實例的方法3.bean的作用域
singleton |
在每一個Spring IoC容器中一個bean定義相應一個對象實例。 |
prototype |
一個bean定義相應多個對象實例。每次調用都創建一個實例 |
request |
在一次HTTP請求中。一個bean定義相應一個實例;即每次HTTP請求將會有各自的bean實例。 它們根據某個bean定義創建而成。該作用域僅在基於web的Spring |
session |
在一個HTTP 該作用域僅在基於web的Spring |
global session |
在一個全局的HTTP |
4.initi-method和destroy-method
假設非常多bean擁有同樣名字的初始化方法和銷毀方法,能夠在beans元素中定義default-init-method和default-destroy-method第三章
1.自己主動裝配與自己主動檢測
自己主動裝配:讓spring自己主動識別怎樣裝配bean的依賴關系。降低對<property>元素的使用。
自己主動檢測:讓spring自己主動識別哪些類須要配置成spring Bean,降低對<bean>元素的使用。
2.4種類型的自己主動裝配
1.byName:尋找和屬性名同樣的bean,若找不到。則裝不上。
2.byType:尋找和屬性類型同樣的bean,找不到,裝不上,找到多個拋異常。
3.constructor:查找和bean的構造參數一致的一個或多個bean,若找不到或找到多個。拋異常。
依照參數的類型裝配
4.autodetect: 首先嘗試constructor進行自己主動裝配。然後再嘗試byType.
<bean id="bar" class="Bar" autowire="byName"/>
3.@[email protected]
@Autowired有required屬性,@Inject沒有。所以inject註解所標註的依賴關系必須存在,假設不存在就拋出異常
4.自己主動檢測與過濾條件
首先改動beans.xml。使用<context:component-scan>替代<bean>用@Component 等來標註類 在使用自己主動檢測bean 的同一時候,我們還能夠通過過濾組件來定義我們的掃描策略。通過為<context:component-config/>配置<context:include-filter/>和<context:exclude-filter/>來實現。
這兩個過濾組件的作用正好相反,<context:include-filter/>告知哪些類須要被註冊,<context:exclude-filter/>告知哪些類不須要註冊。
比如:
<context:component-scan>
<context:include-filter type=”assigable”expression=”com.springinaction.springidol.Instrument”/>
</context:component-scan>
type與expression的聯合使用使繼承Instrument的類註冊為Spring bean。
5.限定依賴
@Qualifier("XXX") 中的 XX是 Bean 的名稱。所以 @Autowired 和 @Qualifier 結合使用時,自己主動註入的策略就從 byType 轉變成 byName 了。
@Autowired 能夠對成員變量、方法以及構造函數進行凝視,而
@Qualifier 的標註對象是成員變量、方法入參、構造函數入參。
第四章
1.AOP的術語
這個內容有點多。直接轉載了。1、連接點(Joinpoint)
程序運行的某個特定位置:如類開始初始化前、類初始化後、類某個方法調用前、調用後、方法拋出異常後。這些代碼中的特定點,稱為“連接點”。Spring僅支持方法的連接點。即僅能在方法調用前、方法調用後、方法拋出異常時以及方法調用前後這些程序運行點織入增強。
2、切點(Pointcut)
每一個程序類都擁有多個連接點,如一個擁有兩個方法的類,這兩個方法都是連接點。但在這為數眾多的連接點中。怎樣定位到某個感興趣的連接點上呢?AOP通過“切點”定位特定的連接點。通過數據庫查詢的概念來理解切點和連接點的關系:連接點相當於數據庫中的記錄。而切點相當於查詢條件。一個切點能夠匹配多個連接點。
Spring中,切點通過Pointcut接口進行描寫敘述。
3、通知(Advice)
4、目標對象(Target)
5、織入(Weaving)
1)編譯期織入,這要求使用特殊的Java編譯器;
2)類裝載期織入,這要求使用特殊的類裝載器;
3)執行期動態代理織入,在執行期為目標類加入增強生成子類的方式。
Spring採用動態代理織入。而AspectJ採用編譯期織入和類裝載期織入。
6、切面(Aspect)
切面由切點和通知組成,它既包含了橫切邏輯的定義,也包含了連接點的定義。Spring AOP就是負責實施切面的框架。它將切面所定義的橫切邏輯織入到切面所指定的連接點中。
7、其它基礎知識
2.通過XML配置切面
這個能夠隨便找個樣例。非常好理解 如:<aop:config> 5 <!-- 6 切入點表達式 7 --> 8 <aop:pointcut expression="execution(* cn.itcast.spring.aop.sh.PersonDaoImpl.*(..))" id="perform"/> 9 <aop:aspect ref="myTransaction"> 10 <!-- 11 <aop:before method="beginTransaction" pointcut-ref="perform"/> 12 <aop:after-returning method="commit" pointcut-ref="perform" returning="var"/> 13 --> 14 <aop:after method="finallyMethod" pointcut-ref="perform"/> 15 <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/> 16 <aop:around method="aroundMethod" pointcut-ref="perform"/> 17 </aop:aspect> 18 </aop:config>
3.註解切面
@Component("myTransaction") 26 @Aspect 27 public class MyTransaction extends HibernateUtils{ 28 private Transaction transaction; 29 30 @Pointcut("execution(* cn.itcast.spring.aop.annotation.sh.PersonDaoImpl.*(..))") 31 private void aa(){}//方法簽名 返回值必須是void 方法的修飾符最好是private ,aa是隨便定義的 做類比 32 33 @Before("aa()") 34 public void beginTransaction(JoinPoint joinpoint){ 35 this.transaction = sessionFactory.getCurrentSession().beginTransaction(); 36 } 37 38 @AfterReturning(value="aa()",returning="val") 39 public void commit(Object val){ 40 this.transaction.commit(); 41 }
第五章
1.可能拋出SQLException的常見問題
1)應用程序無法連接數據庫
2)查詢語法粗偶
3)查詢中使用的表或列不存在
4)視圖插入或更新的數據違反了數據庫的完整性約束
2.ORM的一些特性
1)延遲載入
比方我們要查詢一組PurchaseOrder對象。每一個對象都包括一個LineItem對象所形成的集合。
假設僅僅關心PurchaseOrder對象。那麽能夠延遲載入lineitem對象。可是會把一次查詢分解成多次。
2)預先抓取
與延遲載入相對。預先抓取能夠在一個操作中一起提取出lineitem對象,節省多次查詢的成本。
3)級聯
更改數據庫的表會同一時候改動其它表。
3. @repository註解
在類上使用這個註解。會為我們做兩件事。首先,會被自己主動檢測到。不必聲明bean。另外。假設在Spring配置文件裏聲明了PersistenceExceptionTranslationPostProcessor,[email protected](advisor)。這樣就會捕獲全部平臺相關的異常而且以Spring的非檢查型數據訪問異常的形式又一次拋出。
第六章
能夠參考http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/
對Spring事務有具體解說
1.事務的4個特性
ACID
原子性(atomic):事務中的所有操作要麽所有發生要不所有不發生。當中隨意一個活動失敗,整個事務也失敗而且回滾。
一致性(Consistent):一旦事務完畢,系統必須確保它所建模的業務處於一致的狀態。
隔離性(Isolated): 並發事務之間互相影響的程度,比方一個事務會不會讀取到還有一個未提交的事務改動的數據。在事務並發操作時,可能出現的問題有:
臟讀:事務A改動了一個數據。但未提交,事務B讀到了事務A未提交的更新結果,假設事務A提交失敗,事務B讀到的就是臟數據。
不可反復讀:在同一個事務中,對於同一份數據讀取到的結果不一致。
比方。事務B在事務A提交前讀到的結果。和提交後讀到的結果可能不同。
不可反復讀出現的原因就是事務並發改動記錄。要避免這樣的情況。最簡單的方法就是對要改動的記錄加鎖,這回導致鎖競爭加劇,影響性能。還有一種方法是通過MVCC能夠在無鎖的情況下,避免不可反復讀。
幻讀:在同一個事務中。同一個查詢多次返回的結果不一致。
事務A新增了一條記錄,事務B在事務A提交前後各運行了一次查詢操作。發現後一次比前一次多了一條記錄。幻讀是由於並發事務添加記錄導致的,這個不能像不可反復讀通過記錄加鎖解決,由於對於新增的記錄根本無法加鎖。須要將事務串行化。才幹避免幻讀。
事務的隔離級別從低到高有:
Read Uncommitted:最低的隔離級別。什麽都不須要做。一個事務能夠讀到還有一個事務未提交的結果。
全部的並發事務問題都會發生。
Read Committed:僅僅有在事務提交後,其更新結果才會被其它事務看見。能夠解決臟讀問題。
Repeated Read:在一個事務中。對於同一份數據的讀取結果總是同樣的。不管是否有其它事務對這份數據進行操作,以及這個事務是否提交。能夠解決臟讀、不可反復讀。
Serialization:事務串行化運行。隔離級別最高,犧牲了系統的並發性。
能夠解決並發事務的全部問題。
通常。在project實踐中,為了性能的考慮會對隔離性進行折中。
持久性(Durability)
事務提交後。對系統的影響是永久的。
一般涉及到把結果存儲到數據庫或其它形式的持久化存儲中。
2.Spring與事務
Spring通過回調機制把實際的事務實現從事務性的代碼中抽象出來。分編碼式事務和聲明式事務。編碼式細粒度。聲明式易用。 Spring並不直接管理事務,而是提供了多種事務管理器。將事務管理的職責托付給各種事務管理器,適用不同場景。(比方Hibernate,JMS等)??3.編碼式事務
能夠方便的使用模板
public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionTemplate transactionTemplate; ...... public boolean transfer(final Long fromId。 final Long toId, final double amount) { return (Boolean) transactionTemplate.execute(new TransactionCallback(){ public Object doInTransaction(TransactionStatus status) { Object result; try { result = bankDao.transfer(fromId, toId, amount); } catch (Exception e) { status.setRollbackOnly(); result = false; System.out.println("Transfer Error!"); } return result; } }); } }
4.聲明式事務
基於 @Transactional 的聲明式事務管理
除了基於命名空間的事務配置方式,Spring 2.x 還引入了基於 Annotation [email protected] [email protected] 能夠作用於接口、接口方法、類以及類方法上。
當作用於類上時,該類的全部 public 方法將都具有該類型的事務屬性,同一時候。我們也能夠在方法級別使用該標註來覆蓋類級別的定義。如清單12所看到的:
清單12. 基於 @Transactional 的事務管理演示樣例配置文件
@Transactional(propagation = Propagation.REQUIRED) public boolean transfer(Long fromId, Long toId, double amount) { return bankDao.transfer(fromId, toId, amount); }
Spring 使用 BeanPostProcessor 來處理 Bean 中的標註,因此我們須要在配置文件裏作例如以下聲明來激活該後處理 Bean,如清單13所看到的:
清單13. 啟用後處理Bean的配置
<tx:annotation-driven transaction-manager="transactionManager"/>
聲明式事務通過事務屬性來定義。事務屬性描寫敘述了事務策略怎樣應用到方法上。
事務隔離級別
上文有事務傳播行為
所謂事務的傳播行為是指,假設在開始當前事務之前。一個事務上下文已經存在,此時有若幹選項能夠指定一個事務性方法的運行行為。
在TransactionDefinition定義中包含了例如以下幾個表示傳播行為的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:假設當前存在事務,則增加該事務;假設當前沒有事務,則創建一個新的事務。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務。假設當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_SUPPORTS:假設當前存在事務。則增加該事務;假設當前沒有事務,則以非事務的方式繼續執行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式執行,假設當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_NEVER:以非事務方式執行,假設當前存在事務,則拋出異常。
- TransactionDefinition.PROPAGATION_MANDATORY:假設當前存在事務,則增加該事務。假設當前沒有事務,則拋出異常。
- TransactionDefinition.PROPAGATION_NESTED:假設當前存在事務,則創建一個事務作為當前事務的嵌套事務來執行;假設當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
這裏須要指出的是。前面的六種事務傳播行為是 Spring 從 EJB 中引入的,他們共享同樣的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 啟動的事務內嵌於外部事務中(假設存在外部事務的話),此時,內嵌事務並非一個獨立的事務,它依賴於外部事務的存在。僅僅有通過外部的事務提交,才幹引起內部事務的提交,嵌套的子事務不能單獨提交。
假設熟悉 JDBC 中的保存點(SavePoint)的概念,那嵌套事務就非常easy理解了,事實上嵌套的子事務就是保存點的一個應用,一個事務中能夠包含多個保存點。每個嵌套子事務。另外。外部事務的回滾也會導致嵌套子事務的回滾。
事務超時
所謂事務超時,就是指一個事務所同意運行的最長時間,假設超過該時間限制但事務還沒有完畢,則自己主動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。
事務的僅僅讀屬性
事務的僅僅讀屬性是指,對事務性資源進行僅僅讀操作或者是讀寫操作。所謂事務性資源就是指那些被事務管理的資源,比方數據源、 JMS 資源,以及自己定義的事務性資源等等。
假設確定僅僅對事務性資源進行僅僅讀操作,那麽我們能夠將事務標誌為僅僅讀的。以提高事務處理的性能。在 TransactionDefinition 中以 boolean 類型來表示該事務是否僅僅讀。
事務的回滾規則
通常情況下。假設在事務中拋出了未檢查異常(繼承自 RuntimeException 的異常),則默認將回滾事務。
假設沒有拋出不論什麽異常。或者拋出了已檢查異常,則仍然提交事務。
這通常也是大多數開發人員希望的處理方式,也是 EJB 中的默認處理方式。可是。我們能夠依據須要人為控制事務在拋出某些未檢查異常時任然提交事務,或者在拋出某些已檢查異常時回滾事務。
Spring In Action讀書筆記