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 ApplicationContext 情形下有效。

session

在一个HTTP Session 中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext 情形下有效。

global session

在一个全局的HTTP Session 中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在portlet上下文中有效。


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.@Autowired和@Inject

@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)

      通知是织入到目标类连接点上的一段程序代码。通知既包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方为信息,所以Spring所提供的增强接口都是带方位名的:BeforeAdvice(方法调用前的位置)、AfterReturningAdvice(访问返回后的位置)、ThrowsAdvice等。

 

4、目标对象(Target)

      通知逻辑的织入目标类。

 

5、织入(Weaving)

      织入是将通知添加到目标类具体连接点上的过程。AOP有三种织入方式:

1)编译期织入,这要求使用特殊的Java编译器;

2)类装载期织入,这要求使用特殊的类装载器;

3)运行期动态代理织入,在运行期为目标类添加增强生成子类的方式。

Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

 

6、切面(Aspect)

切面由切点和通知组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。


7、其他基础知识

      Spring AOP使用了两种代理机制:一种是基于JDK的动态代理,另一种是基于CGLib的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。

      JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。

      CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。

      有研究表明,CGLib所创建的动态代理对象的性能比JDK的所创建的代理对象的性能高了不少。但CGLib在创建代理对象时所花费的时间却比JDK动态代理多,所以对于singleton的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之则适合用JDK动态代理技术。   CGLib不能对目标类中的final方法进行代理。


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,它会给所有@repository注解的类上加一个通知器(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:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题
     通常,在工程实践中,为了性能的考虑会对隔离性进行折中。
 持久性(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 的方式,具体主要涉及@Transactional 标注。@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 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)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

事务的只读属性

事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

事务的回滚规则

通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值