Spring in Action (第二版) 读书笔记
1. 开始Spring之旅
Spring是一个轻量级的DI和 AOP容器框架。
依赖注入:协调依赖对象之间合作的责任从对象自身中转移出来
依赖注入只是Spring提供的一种技术,它支持松山耦合。面向切面编程技术提供了另外一个解耦合的功能,它将应用功能(例如安全和事务)和对象分开。让我们快速地看一下Spring对AOP的支持。
2. 基本Bean装配
不是只有一种Spring容器。Spring提供了多种容器实现,并分为两类。Bean工厂(由org.springframework.beans.factory.BeanFactory接口定义)是最简单的容器,提供了基本的依赖注入支持。应用上下文(由org.springframework.context.ApplicationContext接口定义)建立在Bean工厂基础上,提供了系统架构服务,如:从属性文件中读取文本信息,向有关的时间监听器发布事件。
除了应用上下文提供的附加功能外,应用上下文与Bean工厂的另一个重要区别是关于单实例Bean是如何被载入的。Bean工厂延迟载入所有的Bean,直到getBean()方法被调用时Bean才被创建。应用上下文则聪明一点,它会在上下文启动后预载入所有的单实例Bean。通过预载入单实例Bean,确保当你需要的时候它们已经准备好了,你的应用不需要等待它们被创建。
如果Bean实现了ApplicationContextAware接口,setApplicationContext()方法会被调用。
Spring提供了4种类型的集合配置元素<list><set><map><props>
四种自动装备类型byName, byType, constructor, autodetect
Bean的范围化singleton, prototype
Spring有关单例的概念局限于Spring上下文的范围。不同于正真的单例,正真的单例保证类加载时只有一个类实例,Spring的单例Bean只保证每个应用上下文中只有一个Bean定义的实例---没有禁止使用其他更便利的方法实例化相同类,或者也没有禁止定义实例化相同类的<bean>声明。
3. 高级Bean装配
后处理Bean:BeanPostProcessor
BeanPostProcessor接口为我们提供了两个机会,可以在Bean创建和装配置后修改Bean。PropertyPlaceholderConfigurer可以很好地把Spring的部分配置外部化到属性文件里。
4. 通知Bean
Spring通知是用Java编写的。Spring在运行时通知对象。Spring只支持方法连接点。
Spring AOP的通知具有5种形式,用于指定相对于连接点何时运行通知。
Before(前)、After-return(返回后)、After-throwing(抛出后)、Around(周围)、Introduction(引入)。
声明式AOP
5. 使用数据库
DAO的作用在于提供一种手段读取和写入数据库,他们应该通过在接口的形式提供这种功能,让程序的其他部分能够访问它们。
这些异常都源自于DataAccessException,其特殊之处在于它是个免检异常,换句话说,我们不必捕获Spring抛出的任何数据访问异常。
DataAccessException是Spring的全面哲学在处理收检异常与免检异常时的一个范例。Spring认为,很多异常是由不能在Catch块里处理的问题而导致的,所以与其强迫开发人员编写catch块(通常就是空的),还不如使用免检异常,从而让开发人员决定是否应该捕获异常。
Spring把数据访问过程中固定与变化的部分明确地划分为两类:模板和回调。模板管理过程中的固定部分,而回调处理自定义的数据访问代码。Spring模板类处理数据访问的固定部分---控制事务、管理资源和异常处理。同时,数据处理的异常部分,也就是属于每个程序的部分,包括创建语句、绑定参数、整理结果,是在回调实现中处理的。这为实际应用创建了一个漂亮的框架,让开发人员只关心自己的数据访问逻辑。
配置数据源
1) 使用JNDI数据源:以这种方式配置数据源的好处是它们完全可以在程序之外进行管理。程序本身只需要在需要访问数据库时请求数据源即可。而且,应用程序服务器里管理的数据源通常会被组合起来,从而具有更好的性能。
2)使用数据源连接池
3)基于JDBC驱动的数据源:SimpleConnectionDataSource只是用一个数据库连接,所以不适合多线程程序。而DriverManagerDataSource虽然支持多线程,但它会在每次连接请求时都建立一个连接,这是以性能为代价。由于这些限制,我们强烈建议应该使用数据源连接池。
6. 事务管理
在软件中,要么全有要么全无的操作被称为事务。事务允许你把几个操作组织在一个工作单元中,这个工作单元要么全部发生,要么全都不发生。ACID
1)原子性(Atomic):事务有一个或多个行为捆绑在一起组成,好像是一个单独的工作单元。原子性确保在事务中的所有操作要么都发生,要么都不发生。假如所有行为都成功了,那么相应的事务就是成功的。假如任何一个行为失败了,那么整个事务就失败了,并且被回滚。
2)一致性(Consistent):一旦一个事务结束了(不管成功与否),系统所处的状态和它的业务规则是一致的。用现实中的话,就是所属局应当不会被破坏。
3)隔离性(Isolated):事务应该允许多名用户操作同一个数据,一名用户的操作不会和其他用户的操作混淆。因此,事务必须是相互隔离的,防止并行读写同一个数据的情况发生。注意隔离通常意味着锁定数据库里的记录行和(或)表。
4)持久性(Durable):一旦事务完成,事务的结果应该持久化,这样不管什么样的系统崩溃,他们都将幸免于难。通常把事务的结果保存在数据库或其他形式的持久化存储设备中。
Spring的事务管理支持甚至不需要JTA实现。如果你的应用程序只是用单一的持久化资源,那么Spring就可以使用该持久化机制本身所提供的事务管理支持。这些持久化机制包括JDBC、Hibernate、JDO、OJB等。然而,如果你的应用程序有跨越多个资源的事务需求,那么Spring可以使用第三方的JTAG实现支持分布式(XA)事务。
声明性事务:传播行为、隔离级别、只读、事务超时、回滚规则。
传播行为:传播行为定义关于客户端和被调用方法的边界。Spring定义了7中截然不同的传播行为:PROPAGATION_MANDATORY、PROPAGATION_NESTED、PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED 、PROPAGATION_REQUIRED、PROPAGATION_REQUIRED_NEW、PROPAGATION_SUPPORTS。
传播规则回到了这样一个问题,就是一个新的事务应该被启动或者被挂起,或者是一个方法是否应该在事务性上下文中运行。
隔离级别:定义一个事务可能受其他并发事务活动影响的程度。并发,可能导致以下问题:
1)脏读(Dirty read):脏读发生在一个事务读取了另外一个事务改写但尚未提交的数据时。如果这些改写在稍后被回滚了,那么第一个事务读取的数据就会是无效的。
2)不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每一个查询结果都不同时。这通常是由于另一个并发事务在两次查询之间更新了数据。
3)幻读(Phantom reads):幻读和不可重复读相似。当一个事务读取几行记录后,另一个并发事务插入了一些记录时,幻读就发生了。在后来的查询中,第一个事务就会发现有一些原来没有的额外记录。
Spring的事务隔离级别
1)DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
2)READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
3)READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
4)REPEATABLE_READ 会出幻读(锁定所读取的所有行)
5)SERIALIZABLE 保证所有的情况不会发生(锁表)
回滚规则:在默认设置下,事务只在出现运行异常时回滚,而在出现受阻异常(checked exception)时不回滚(这一行为和EJB中的回滚行为是一致的)。
声明式配置