Chapter 6 Lightweight Containers and Inversion of Control
體會為何叫做BeanFactory?在xml文件中的定義,不管用于何種目的,其實定義的都是對象。只有對象才會有singleton。
rod強調要把BeanFactory保存在ServletContext里,因為創(chuàng)建BeanFactory開銷很大,并且建議使用singleton模式
rod強調interface的重要性,唯此,我們才能任意的更換interface的實現(xiàn),真正體會到無需修改代碼而改變對象行為
Chapter 7 Introducing the Spring Franework
rod在提出Spring時,為何冠以Without EJB?實際上回答這個問題也就是回答Spring的目標是什么?Spring要達到avoiding application code depending on a container。而EJB是離不開EJB container的。
如何讓container即能夠滿足業(yè)務對象之間的依賴關系而又保證業(yè)務對象對于container沒有依賴性?答案就是Ioc和依賴注入Dependency Injection.
EJB其實也是一種Ioc,只不過是Dependency lookup,類似的還有Avalon。(尼瑪,我第一次看到這個鬼東西是用到Jmeter的時候,當時我還以為這是一種數(shù)據(jù)庫緩沖池呢)
你可以把Spring Container看做是一種Ioc Container,TA負責為application object尋找resource或者是collaborators
在web應用中Spring到底扮演的是什么角色?serve as backbone for the logical middle tier of the a J2EE web application. Spring提出的 web application context可以無縫的適應web環(huán)境,被Structs等web層訪問。
root web application context是通過ContextLoaderListener來加載的,ContextLoaderListener在web.xml文件中定義。
Spring的web application context如何服務于J2EE的Context?web application context加載后,作為ServletContext的屬性出現(xiàn)。
Bean Factory是接口定義,它的實現(xiàn)都是Ioc。XmlBeanFactory, DefaultListableBeanFactory…
我們在xml文件中定義Bean的基本信息,這個xml文件作為Ioc的配置文件被各種Bean Factory的實現(xiàn)類(例如XmlBeanFactory, DefaultListableBeanFactory)讀入,加載對象。
對于pluggability,rod認為是定義接口,以及缺省實現(xiàn)implement,這樣就可以解耦合,并且可以很容易的切換到其它實現(xiàn)上。其實這也是Bean factory的實現(xiàn)模式。
The ability to express even strongly typed dependencies on collaborating objects via JavaBean properties and have the satisfied by Ioc is the key to the power of the Spring lightweight container.
如果不把JNDI封裝成factory bean JndiObjectFactoryBean,而僅僅當做是普通的對象,又有什么區(qū)別?那代碼中一定會出現(xiàn)lookup的代碼,而lookup一定要指定resource名稱,這個名稱還必須hard code。Spring的目標是什么?avoid hard code resource lookups for specific environments.如果你不想出現(xiàn)hard code,那你自己就必須維護配置文件(至少實現(xiàn)配置文件解析的功能,就像現(xiàn)在hrms系統(tǒng)需要解析systemConfig.xml文件)
為什么要擴展出那么多的Factory,而不僅僅擴展出一般的Class?K,這個關鍵是不同Factory對應getObject()得到的對象類型是不一樣的啊。不會具有通用性。JNDI和AOP肯定是不一樣的啊。
ApplicationContext本質上還是Bean Factory。
不在于讀了多少文檔,而在于讀懂了多少頁的文檔,享受反復閱讀直至恍然大悟的感覺,夢里尋他千百度,暮然回首,那人卻在燈火闌珊處。只有讀懂了,才能夠理解rod大神的意圖。這樣的機會不會很多,請珍惜!
和讀文檔相比,寫代碼簡直太輕松了。我讀的很慢,至今才讀了兩章。覺得rod的字里行間都有很多東西值得體會。以前還敢說自己懂Spring,現(xiàn)在連了解都不敢說了。似乎又找到以前讀“C++ primer”的感覺了,每晚讀書,都像是在看大片,每個早晨都期待夜晚能早點開始。那是一種享受。
WebApplicationContext提供了一個更加通用的上下文環(huán)境,如果使用ServletContext會帶來對servlet環(huán)境的依賴性。因此建議使用前者。
Spring帶來的好處1. 去掉了各種singletons和factories;2. write application code againest interface; 3. 以統(tǒng)一的方式進行配置管理;4.改善可測試性
Chapter 9 Transaction Management
可以直接使用JTA。誰來提供JTA的實現(xiàn)呢?CMT是一種實現(xiàn),Spring的JtaTransactionManger, 負責授權給J2EE容器的JTA子系統(tǒng)。
Spring事務處理基礎設施的最大好處就是不必綁在JTA上。
Transaction定義包括:Propagation behavior事務傳播類型, isolation level隔離級別, Timeout超時, read-only只讀事務.
Spring的核心接口:PlatformTransactionManger
編程式事務處理,采用TransactionTemplate,只需實現(xiàn)callback。
聲明式事務處理,這并不是Spring所特有的,例如JBoss AOP就是基于AOP的聲明式事務處理。分為兩種方式:AOP ProxyFactoryBean和TransacionProxyFactoryBean.
事務管理策略,包括:JtaTransactionManager, DataSourceTransactionManager, JdoTransactionManager, HibernateTransactionManager.
JtaTransactionManager:如果管理超過一個resource的事務,就需要把事務管理委派給J2EE容器。Spring只是提供了一種接入應用服務器的事務處理的手段。
DataSourceTransactionManager:必須遵守特定的lookup模式,DataSourceUtils.getConnection()。若使用JdbcTemplate這種轉換是自動完成的。
Spring事務支持的最大好處是無需特殊的處理POJO就能夠支持事務處理。另外如果應用是僅僅包含數(shù)據(jù)庫級的事務處理,根本無需任何J2EE server,Tomcat足夠了。
Chapter 10 Persistence
常用的持久化策略:1 transaction script,這是最原始的,就是通過JDBC完成數(shù)據(jù)操作。2 active record,gateway class完成數(shù)據(jù)的數(shù)據(jù)insert,update,delete操作,finder class負責查詢獲取對象。3 O/R mapper,domain class負責業(yè)務邏輯;data mapper負責持久化操作。
DAO J2EE模式:嚴格區(qū)分業(yè)務實現(xiàn)和持久化邏輯。而后者一般會被聚攏在一起,形成DAO interface。
什么情況下不適用O/R mapping?大量使用數(shù)據(jù)查詢以及集合訪問,以及數(shù)據(jù)的批量修改,(heavy use of set access and aggregate functions, and batch updates of many rows);如果就是很簡單的數(shù)據(jù)訪問其實也沒必要用O/R mapping。
什么情況適用O/R mapping?1 domain object具有典型的load/edit/store工作流(如果domain object設計很復雜,可以用不同的操作導致不同字段的更新,這種場景不適用采用O/R mapping);2 一次獲得大量對象,但是修改和刪除卻是單獨進行3 大量的對象是讀操作 4 沒有特殊的SQL優(yōu)化的需求
O/R mapping最主要的好處就是避免JDBC的重復代碼,另一個好處就是transparent persistence。
如何理解transparent persistence?就是你無需在application code里檢查對象是否修改,實際發(fā)生修改的對象會自動提交。(only actual changes will be committed, there is no need for dirty checking in application code)
資源管理resource handler包括兩方面:connection factory和connection。對于JDBC,connection factory是DataSouce, connection是Connection;對于hibernate,前者是SessionFactory,后者是Session。
Hibernate是如何實現(xiàn)disassociate和reassociate的?
Business Objects只關注業(yè)務邏輯,不關注如何獲取和保存數(shù)據(jù);Data Access Objects實現(xiàn)持久化策略,它暴露出DAO接口給Business Object使用,并且要參與到Transaction里,但是它不負責驅動Transaction。
Transaction的劃分是Business Object的責任。
即使有了各種O/R mapping工具,還是應該使用DAOs對O/R mapping層進行封裝。原因有三:1 便于測試 2 DAOs offers a clear, strongly typed persistence API for domain 3 DAOs allow finder methods with domain arguments.
DAO接口總是和特定的持久化策略綁定。就是說沒可能DAO接口即可以通過O/R mapping來實現(xiàn),又可以通過JDBC來實現(xiàn),最直接的原因是操作的粒度是不同的。但是如果僅僅是read-only DAO,是可以通過O/R mapping來實現(xiàn),又可以通過JDBC來實現(xiàn)。
DAOs的最重要的目標是allow for leveraging vendor extensions and testability.
DAOs的類型,rod例舉了5種,其實有用的不過3種:Classic JDBC-based DAO, DAO for a specific transparent persistence tool, Portable read-only DAO.
DAO 設計問題,1 數(shù)據(jù)訪問粒度data access granularity as your business object allow.過細沒有意義。rod甚至認為區(qū)分create和update都是木有必要的,因為我們可以通過ID屬性判斷出是何種操作。
DAO 設計問題,2 透明的持久化和對象狀態(tài);
DAO 設計問題,3 事務范圍和延遲加載。Transaction必須在一次request里完成,不能跨多次request。延遲加載在Transaction之外是不起作用的。這就會帶來一個新問題,如果business操作結束后,也就是說Transaction結束后,延遲加載沒有完成怎么辦?一種解決方法是在視圖渲染(view rendering)過程中依然保持住connection。
DAO基礎設施問題, 1 封裝 2 參與事務處理 3 異常管理。Spring很好解決了這3個問題。不僅考慮持久化工具也要考慮為DAOs考慮適合的基礎設施。Spring provide transaction management and other glue between business objects and data access objects.
Spring對JDBC的支持:template class和operation objects,這其實就是對JDBC的抽象,目前是簡化編碼,最大限度的避免不必要的錯誤。并且Spring為此提供單獨的jar包,這樣可以在沒有Spring上下文的環(huán)境下單獨使用。另外在Exception方面,Spring進行了細化,增強了可讀性。
Spring對Hibernate的支持:HibernateTemplate。
我曉得rod為何如此組織這章內容。倒著看,Spring Framework支持的Data Access實際是基于Data Access Object Pattern的;說到DAO pattern,就會涉及Data Access Technology(JDBC,hibernate),再往上推,豈不就是我們到底選擇何種技術實現(xiàn)Persistence策略。rod這最后的包袱抖的。
chapter 14 Unit Testing and Testability
單元測試的目標。單元測試是獨立的測試每個類。Unit test is about testing each class in isolation.
導致代碼不可測試的問題,1 Singleton pattern 2 Static locator method 3 Classes with too many responsibility 4 Programming to classes, rather than interface
Classes should be testable not only in isolation from each other, but apart from their runtime environment.
Singleton pattern帶來的問題:很難用test stub來替代,所有的調用代碼都必須明確指定類。Ioc容器也無法創(chuàng)建和管理Singleton。J2EE應用中,可以通過ServletContext來實現(xiàn)Singleton。
Static locator method帶來的問題:這意味木有接口定義,只能是抽象類;并且static的方法也是不能重載override的。
標準類庫也會帶來代碼不可測試的問題,例如JavaMail, JNDI。前者通過org.springframework.mail和org.springframework.javamail來解決,后者通過org.springframework.jndi.SimpleNamingContextBuilder來解決
rod給出7種可以改善可測試性的技術,1. Code to interfaces rather than classes. 2. Use the Strategy design pattern. 3. Consider the Law of Demeter. 4. Minimize dependence on environment-specific APIs. 5. Give each object a manageable and consistent set of responsibilities. 6. Hide implementation details. 7. Refactor into methods to allow overriding at test time.正如TA所說,這些技術其實也是good design的設計思路。
如何寫有效的Test case?Negative Tests測試異常部分;Equivalence Partitioning等價劃分其實就是測試case條件語句。
Test case Code Practice,強調test case應該是Self_document,就是說通過test case我們就可以了解被測試對象的行為,尤其是Exception部分的測試;除非別無選擇,否則不要依賴外部配置;如果有必要對Test case也要進行重構。
我不大明白rod為何要把這章包括進來,rod一再強調TDD的重要性,但其實TDD和任何的framework都無關啊。
了解一個復雜系統(tǒng)或者是設計很糟糕的系統(tǒng)的最好方法就是去寫test case,不僅可以掌握各種系統(tǒng)功能,同時這些test case在重構過程也是重要的測試手段。
Others
Spring的配置管理會導致大量的代碼再也無法通過混淆器來混淆。從而導致代碼無法加密。總不能先混淆,然后再修改Spring的配置文件吧。