Chapter 6 Lightweight Containers and Inversion of Control
体会为何叫做BeanFactory?在xml文件中的定义,不管用于何种目的,其实定义的都是对象。只有对象才会有singleton。
rod强调要把BeanFactory保存在ServletContext里,因为创建BeanFactory开销很大,并且建议使用singleton模式
rod强调interface的重要性,唯此,我们才能任意的更换interface的实现,真正体会到无需修改代码而改变对象行为
Chapter 7 Introducing the Spring Franework
rod在提出Spring时,为何冠以Without EJB?实际上回答这个问题也就是回答Spring的目标是什么?Spring要达到avoiding application code depending on a container。而EJB是离不开EJB container的。
如何让container即能够满足业务对象之间的依赖关系而又保证业务对象对于container没有依赖性?答案就是Ioc和依赖注入Dependency Injection.
EJB其实也是一种Ioc,只不过是Dependency lookup,类似的还有Avalon。(尼玛,我第一次看到这个鬼东西是用到Jmeter的时候,当时我还以为这是一种数据库缓冲池呢)
你可以把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环境,被Structs等web层访问。
root web application context是通过ContextLoaderListener来加载的,ContextLoaderListener在web.xml文件中定义。
Spring的web application context如何服务于J2EE的Context?web application context加载后,作为ServletContext的属性出现。
Bean Factory是接口定义,它的实现都是Ioc。XmlBeanFactory, DefaultListableBeanFactory…
我们在xml文件中定义Bean的基本信息,这个xml文件作为Ioc的配置文件被各种Bean Factory的实现类(例如XmlBeanFactory, DefaultListableBeanFactory)读入,加载对象。
对于pluggability,rod认为是定义接口,以及缺省实现implement,这样就可以解耦合,并且可以很容易的切换到其它实现上。其实这也是Bean factory的实现模式。
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,而仅仅当做是普通的对象,又有什么区别?那代码中一定会出现lookup的代码,而lookup一定要指定resource名称,这个名称还必须hard code。Spring的目标是什么?avoid hard code resource lookups for specific environments.如果你不想出现hard code,那你自己就必须维护配置文件(至少实现配置文件解析的功能,就像现在hrms系统需要解析systemConfig.xml文件)
为什么要扩展出那么多的Factory,而不仅仅扩展出一般的Class?K,这个关键是不同Factory对应getObject()得到的对象类型是不一样的啊。不会具有通用性。JNDI和AOP肯定是不一样的啊。
ApplicationContext本质上还是Bean Factory。
不在于读了多少文档,而在于读懂了多少页的文档,享受反复阅读直至恍然大悟的感觉,梦里寻他千百度,暮然回首,那人却在灯火阑珊处。只有读懂了,才能够理解rod大神的意图。这样的机会不会很多,请珍惜!
和读文档相比,写代码简直太轻松了。我读的很慢,至今才读了两章。觉得rod的字里行间都有很多东西值得体会。以前还敢说自己懂Spring,现在连了解都不敢说了。似乎又找到以前读“C++ primer”的感觉了,每晚读书,都像是在看大片,每个早晨都期待夜晚能早点开始。那是一种享受。
WebApplicationContext提供了一个更加通用的上下文环境,如果使用ServletContext会带来对servlet环境的依赖性。因此建议使用前者。
Spring带来的好处1. 去掉了各种singletons和factories;2. write application code againest interface; 3. 以统一的方式进行配置管理;4.改善可测试性
Chapter 9 Transaction Management
可以直接使用JTA。谁来提供JTA的实现呢?CMT是一种实现,Spring的JtaTransactionManger, 负责授权给J2EE容器的JTA子系统。
Spring事务处理基础设施的最大好处就是不必绑在JTA上。
Transaction定义包括:Propagation behavior事务传播类型, isolation level隔离级别, Timeout超时, read-only只读事务.
Spring的核心接口:PlatformTransactionManger
编程式事务处理,采用TransactionTemplate,只需实现callback。
声明式事务处理,这并不是Spring所特有的,例如JBoss AOP就是基于AOP的声明式事务处理。分为两种方式:AOP ProxyFactoryBean和TransacionProxyFactoryBean.
事务管理策略,包括:JtaTransactionManager, DataSourceTransactionManager, JdoTransactionManager, HibernateTransactionManager.
JtaTransactionManager:如果管理超过一个resource的事务,就需要把事务管理委派给J2EE容器。Spring只是提供了一种接入应用服务器的事务处理的手段。
DataSourceTransactionManager:必须遵守特定的lookup模式,DataSourceUtils.getConnection()。若使用JdbcTemplate这种转换是自动完成的。
Spring事务支持的最大好处是无需特殊的处理POJO就能够支持事务处理。另外如果应用是仅仅包含数据库级的事务处理,根本无需任何J2EE server,Tomcat足够了。
Chapter 10 Persistence
常用的持久化策略:1 transaction script,这是最原始的,就是通过JDBC完成数据操作。2 active record,gateway class完成数据的数据insert,update,delete操作,finder class负责查询获取对象。3 O/R mapper,domain class负责业务逻辑;data mapper负责持久化操作。
DAO J2EE模式:严格区分业务实现和持久化逻辑。而后者一般会被聚拢在一起,形成DAO interface。
什么情况下不适用O/R mapping?大量使用数据查询以及集合访问,以及数据的批量修改,(heavy use of set access and aggregate functions, and batch updates of many rows);如果就是很简单的数据访问其实也没必要用O/R mapping。
什么情况适用O/R mapping?1 domain object具有典型的load/edit/store工作流(如果domain object设计很复杂,可以用不同的操作导致不同字段的更新,这种场景不适用采用O/R mapping);2 一次获得大量对象,但是修改和删除却是单独进行3 大量的对象是读操作 4 没有特殊的SQL优化的需求
O/R mapping最主要的好处就是避免JDBC的重复代码,另一个好处就是transparent persistence。
如何理解transparent persistence?就是你无需在application code里检查对象是否修改,实际发生修改的对象会自动提交。(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是如何实现disassociate和reassociate的?
Business Objects只关注业务逻辑,不关注如何获取和保存数据;Data Access Objects实现持久化策略,它暴露出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来实现,又可以通过JDBC来实现,最直接的原因是操作的粒度是不同的。但是如果仅仅是read-only DAO,是可以通过O/R mapping来实现,又可以通过JDBC来实现。
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 数据访问粒度data access granularity as your business object allow.过细没有意义。rod甚至认为区分create和update都是木有必要的,因为我们可以通过ID属性判断出是何种操作。
DAO 设计问题,2 透明的持久化和对象状态;
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上下文的环境下单独使用。另外在Exception方面,Spring进行了细化,增强了可读性。
Spring对Hibernate的支持:HibernateTemplate。
我晓得rod为何如此组织这章内容。倒着看,Spring Framework支持的Data Access实际是基于Data Access Object Pattern的;说到DAO pattern,就会涉及Data Access Technology(JDBC,hibernate),再往上推,岂不就是我们到底选择何种技术实现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容器也无法创建和管理Singleton。J2EE应用中,可以通过ServletContext来实现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都无关啊。
了解一个复杂系统或者是设计很糟糕的系统的最好方法就是去写test case,不仅可以掌握各种系统功能,同时这些test case在重构过程也是重要的测试手段。
Others
Spring的配置管理会导致大量的代码再也无法通过混淆器来混淆。从而导致代码无法加密。总不能先混淆,然后再修改Spring的配置文件吧。