Spring3.2.0 (Spring版本)

 

 

目录简介:

spring-framework-3.0.2.RELEASE-dependencies.zip
名称:Spring3.0.2版本发布整合资源jar包
作用:可以在其中找到Spring开发过程中所使用的绝大多数jar包
介绍:各种各样的技术


spring-framework-3.2.0.RELEASE-dist.zip
名称:Spring3.2.0框架资源包
作用:开发Spring使用的基础资源信息


文件夹介绍:
docs  API帮助文档和官方手册
libs  jar包
包括
源码包 *-source.jar
文档包 *-javadoc.jar
schema  
开发使用的XML约束文档源文件,dtd,schema
license.txt  说明文件
notice.txt  说明文件
readme.txt  说明文件


jar包整理:
核心jar包
spring-beans-3.2.0.RELEASE.jar
spring-context-3.2.0.RELEASE.jar
spring-core-3.2.0.RELEASE.jar
spring-expression-3.2.0.RELEASE.jar
日志相关jar包(从依赖资源中获取)
commons-logging-1.1.1.jar
日志整合,与slf4j类似,由Apache提供
位置:依赖资源包下的spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.logging\1.1.1
log4j-1.2.16.jar
schema:开发使用的XML约束文档源文件
dtd
schema


Spring 简单介绍(备注:有时间可以了解一下EJB)
Spring功能非常强大,能够服务于J2EE开发过程中的各个层面
表现层:SpringMVC
逻辑层:Bean管理、AOP、事务管理
数据层:Spring JDBCTemplate


Spring是一个基于JAVA的轻量级J2EE应用框架
基于Java
轻量级
JEE框架:Spring可以为J2EE开发过程中的三层每层都带来实现技术

Struts:表现层框架  Hibernate:数据层框架


简单的来说,Spring的本质就是 
自动创建工厂类,依赖配置文件完成
Spring核心技术
IOC:控制反转
AOP:面向切面编程/面向方面编程
Spring中的内容
包含有核心容器,AOP,数据访问(主要做集成),WEB访问(主要做集成)
Spring的作用
Spring是一个超级的“黏合平台”,将很多技术黏合在一起,形成一个整体,是每个组件发挥其最大的功效


Spring构造器初始化对象原理及流程
1.使用ApplicationContext对象可以将对应的xml文件进行加载
2.搜索beans元素下都多少个bean元素
3.对每一个bean元素读取其class属性值
4.根据该值使用反射,创建对应的对象
如果读取到了该bean元素下有property元素
通过配置的property的name值,生成一个setter方法
使用反射构建该方法对应的Method对象
使用创建的对象,加上后面配置的值,invoke(obj,val)
5.创建一个Map<String, Object>
使用id作为key
使用反射创建的对象作为value
将所有的bean初始化完毕后,放入到map
6.调用getBean("beanId")方法,实际上是使用参数作为map的key
访问其对应的数据


Bean的初始化方式
Spring管理对象均以Bean的形式呈现,Bean就是Java对象
类构造器初始化(主流)
使用默认的无参构造方法来创建Bean对象,要求提供对应的构造方法
静态工厂方法初始化(非主流:了解)
该模式用于兼容早期系统,提供一个静态工厂类,然后定义Bean使用下列格式:
<!-- 静态工厂初始化 -->
<!-- class:静态工厂的类名 -->
<!-- factory-method:静态工厂中用于创建对象的方法 -->
<bean id="bean2" class="cn.smile.bean.xml.Bean2StaticFactory" factory-method="getInst">
</bean>
实例化工厂方法初始化(非主流:了解)
首先将实例工厂类配置为Bean
<!-- 实例工厂初始化  -->
<!-- 必须先创建实例工厂对应的Bean -->
<bean id="instFactory" class="cn.smile.bean.xml.Bean3InstFactory"></bean>
<bean id="bean3" factory-bean="instFactory" factory-method="getInst"></bean>


Bean的作用域
Spring中的Bean默认创造出的对象是同一个,也就是单例的,通过修改bean元素的scope属性可以控制创建出的实例的作用域
<bean id="beanScope" scope="singleton" class="cn.smile.spring.scope.Bean1"> </bean>


scope的取值可以使用如下值
singleton  单例
prototype  非单例
request  创建该Bean,并调用requestsetAttribute("beanId", beanObj);
session / globalSession全局Session (分布式服务器)


Bean的生命周期
Bean的初始化过程已经被Spring完全包装起来了,无法人工干预
Spring预留了两个回调方法的入口
回调方法:定义出来完成一定的功能,提供给调用者/服务器/上层容器调用的方法,叫做回调方法


由于Bean的声明周期由Spring管理,Spring在没有关闭其IoC容器前,将不销毁所管理的Bean,因此必须将其手动关闭才可以销毁Spring所控制的Bean实例


ApplicationContext接口并不提供关闭操作,使用其子类对象ClassPathXmlApplicationContext进行关闭操作


注意:销毁操作只能用于单例的对象,即scope属性为singletion的对象
非单例的Bean对象的回收交由JVM完成--GC


Bean的属性注入
Spring支持使用两种方式为Bean注入属性


构造器注入
提供对应的构造方法
配置中设置构造方法的参数
<!-- 构造器注入属性 -->
<!-- construtor-arg:使用构造器传递参数 -->
<!-- value:赋值 -->
<bean id="bean6" class="cn.smile.bean.xml.Bean6" >
<constructor-arg value="Smile"/>
<constructor-arg value="2017"/>
</bean>  
注意:如果类型匹配不成功,可以为配置中指定index索引属性,规范构造器中参数的位置


Setter注入(重点)
注入简单类型:String,基本数据类型封装类
提供对应要注入的属性
为每个要注入的属性提供对应的标准封装setter方法
在配置中为Bean指定要注入的属性,使用property元素 name="属性名" value="值"
<property name="name" value="Smile"/>


注入引用类型:对象
提供对应要注入的属性
为每个要注入的属性提供对应的标准封装setter方法
将要注入的引用类型对象配置为Spring管理的资源,bean


<!-- 为一个类注入引用类型的对象,必须将该对象设置为spring的bean -->
<!-- 声明bean7中使用的引用类型资源 -->
<bean id="abc" class="cn.smile.bean.xml.Bean7Use"></bean>
<!-- 在Bean的属性注入中,使用ref引用对应的资源 ref=”beanId/beanName” -->
<!-- setter注入 -->
<!-- name:属性名 -->
<!-- value:简单类型的值 -->
<!-- ref:引用别的Bean,beanId/beanName -->
<bean id="bean7" class="cn.smile.bean.xml.Bean7">
<property name="name" value="Smile"/>
<property name="age" value="2017"/>
<property name="use" ref="abc"/>
</bean>


p命名空间————属性注入的格式优化
Spring2.5引入全新的命名空间p,有效的简化了配置的内容,缩短配置信息
在约束信息中加入使用命名空间p
xmlns:p="http://www.springframework.org/schema/p"


属性注入格式优化
常量属性格式  p:<属性名>="属性值"
引用bean对象格式 p:<属性名>-ref="bean名称"


<bean id="bean8" class="cn.smile.bean.xml.Bean7"
p:name="smile2"
p:age="2014"
p:use-ref="abc"
>
</bean>


Spring EL表达式
Spring3.0引入全新的SpEL(Spring Expression Language)Spring表达式语言,使用表达式语言可以是属性注入格式进一步简化,同时支持包括对象注入,集合注入,集合访问,实例方法引用,静态方法引用等多种格式。


Spring3.0提供了专用的EL表达式,用于描述更多的格式,详情参考《Spring_表达式语言.pdf》


所有格式统一使用 value="......"
常量  #{10}  #{3.14}  #{2e5}  #{'Smile'}
引用Bean  #{beanId}
引用Bean属性  #{beanId.propertyName}
引用Bean方法  beanId.methodName().method2()
引用静态方法  T(java.lang.Math).PI
运算符支持  #{3 lt 4 == 4 ge 3}
正则表达式支持  #{user.name matches '[a-z]{6,}'}
集合支持  #{likes[3]}


setter注入集合属性(了解)
Spring属性注入还支持集合对象的使用,常见的集合对象注入如下:
List/数组
Set
Map
Properties


团队开发合作模式
当开发人员过多时,如果所有bean都配置到同一个配置文件applicationContext.xml中,会引起文件巨大,查找不方便的现象出现
Spring提供了团队开发的xml配置格式
将多个bean配置到不同的applicationContext文件中(多个)
文件命名规范:applicationContext-功能模块名.xml
applicationContext-user.xml
applicationContext-order.xml
applicationContext-device.xml
提供一个主配置文件将所有的公共bean配置到主配置文件中(1个)
applicationContext.xml


当配置中需要导入其他的配置文件中的bean,使用import元素完成
<!-- 加载主配置文件 -->
<import resource="applicationContext.xml"/>
加载上下文对象时,使用多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-user.xml","application.xml");
冲突问题:
如果同一个配置文件中,具有多个相同id的Bean,抛出异常
如果多个不同的配置文件中,具有多个相同id的Bean,以最后加载的为准

可以为bean声明name属性,丰富该bean的调用名称 name= "beanName1,beanName2,......"


使用注解定义bean
@Component
功能:指定对应的类为Spring控制的bean
格式:定义在类的上方,可以为类指定bean名称
定义UserDaoImpl类为Spring控制的bean,未指定名称
@Component
public class UserDaoImpl implements UserDAO{
...
}
定义UserDAOImpl类为Spring控制的bean,名称"userDAO"
@Component("userDao")
public class UserDAOImpl implements UserDAO{
...
}
bean的名称可以定义多个,如@Component("u1,u2,u3")


需要在配置中添加
xmlns:context="http://www.springframework.org/schema/context"


http://www.springframework.org/schema/context
http://www.springframework.org/schema/beans/spring-context.xsd

<!-- 开启自动扫描路径,含子路径 -->
<context:component-scan base-package="cn.smile"/>


注解格式注入无需设置setter方法


Spring2.5还定义了3个@Component的衍生注解,用于后期版本中对其功能进行深层次的扩展
@Repository 用于对数据层实现类进行标注
@Service 用于对业务逻辑层实现类进行标注
@Controller 用于对控制层实现类进行标注
目前上述三种注解与@Component功能完全相同,仅仅是名称上的区别


使用注解定义属性注入
@AutoWired
功能:标注类的成员变量为自动装配注入属性
格式:定义在成员变量的上方
参数:require
可选值:true(默认值)/false
作用:标识该属性是否必须注入,如果未对其指定注入的值,则系统抛出异常
注入不同类别的属性需要使用不同的注解
简单类型:@Value
对象类型:@Qualifier


自动装配类型识别(引用类型)
注入属性类型为class
如果类名对应的类只有一个,注入成功
如果类名对应的类有多个,注入失败
注入属性类型为interface
如果不存在对应接口的实现类,注入失败
如果对应接口的实现类为一个,注入成功
如果对应接口的实现类为多个,注入失败
如果对应接口的实现类指定有bean名称,则按照属性定义的名称进行匹配
如果存在对应名称的自动装配bean,注入成功  
如果存在对应名称的自动装配bean,注入失败  


@Qualifier
功能:为属性注入的Bean类型的值
格式:定义在成员变量的上方
注意:该注解与@Autowired配合使用
@Qualifier必须给出注入的bean的名称
如果对应的bean不存在,抛出异常,注入失败
为@Autowired指定参数required=false,避免注入失败时候抛出异常


使用注解@Resource为属性注入(了解)
Spring提供对JSR-250中定义@Resource标准注解的支持。
@Resource与@Autowired功能非常相似,用于bean的自动装配,格式略有区别


整合JUnit
使用JUnit整合Spring可以有效的加快测试速度,避免大量繁琐的重复代码,获取配置信息的任务交由JUnit来完成
使用JUnit整合Spring需要导入对应的测试包
spring-test-3.2.0.RELEASE.jar
需要在MyEclipse中添加JUnit,和导入jar包类似,选择Add Library,然后选择一个JUnit的版本即可


具体步骤:
要求为测试类设置类运行器,定义在类的上方
//设置当前类的JUnit测试的类运行器由Spring提供
@RunWith(SpringJUnit4ClassRunner.class)
设置加载的配置文件,定义在类的上方
//设置加载的配置文件
@ContextConfiguration(locations="classpath:applicationContext.xml")
将要测试的Bean使用注解的格式注入到当前测试类中
//Junit测试必须使用
@Autowired
@Qualifier("bean1")
private Bean1 bean;
在测试方法中直接使用注入的Bean进行测试
@Test
public void fn(){
bean.fn();
}


小结:
初始化Bean——构造方法初始化
Bean作用域——scope   prototype
Bean的生命周期
Bean属性注入(重点)
简单类型注入(包括String)
value = 值
引用类型注入
ref = beanId/beanName
团队开发
import
bean冲突


AOP简介
AOP(Aspect Oriented Programing)面向切面编程,一种软件工程的编程范式


OOP(Object Oriented Programing)面向对象编程:制作程序时,设计模型,运行时,靠对象运行,是一种软工的编程范式


AOP联盟:一个组织,致力于AOP的发展研究JRC


AOP思想:AOP关注的是程序中的共性功能,开发时,将共性功能抽取出来制作成独立的功能模块,此时原始功能中将不具有这些被抽取出的共性功能代码。在当时具有被抽取的共性功能的模块运行时候,将共性功能,模块进行运行,即可完成原始的功能。


优点:加强代码的复用性,同时程序开发时可以只考虑个性化的功能,不需要考虑共性功能


AOP基本概念
连接点(Joinpoint):具有特定功能的方法,一般方法
切入点(Pointcut):具有共性功能的方法的统称一种称呼方式
目标对象(Target Object):包含切入点的类
通知(Advice):将共性功能抽取走,制作成独立的功能模块
切面(Aspect):切入点与通知匹配的一种情况

AOP代理(AOP Proxy):运行过程使用AOP创建代理对象进行运行,运行过程中将抽取的功能执行,该过程由AOP自动完成,所以称为AOP代理

织入(Weaving):称将抽取的功能加入原始功能运行的整个过程叫做织入(动态),织入控制的是字节码


引入(Introduction):完整的方法或成员变量抽取加入的过程叫做引入


工作流程:
开发时,制作功能类(目标对象),将其中的方法中的通用功能(通知)抽取出来,制作成独立的类(通知类),原始目标对象中的方法(切入点)不再进行通用功能的制作。该功能被抽取后,无法完成完整的业务逻辑,需要在运行时将通知加入到对应的位置执行。为了完成此操作,必须将切入点与通知进行一对一的对应关系设定(切面)。
运行流程:
运行时,Spring一直监控切面中所配置的切入点对应的方法的执行,发现执行了该方法,使用AOP的代理机制,创建代理对象(AOP代理),将原始方法(切入点)与通知进行融合,形成一个完整的业务逻辑进行运行,此过程称为织入。


XML开发AOP
jar包
Spring核心包(4个)
Spring日志包(2个)
AOP包(4个)
Spring进行AOP开发(1个)(3.2资源包)
spring-aop-3.2.0.RELEASE.jar
Spring整合AspectJ框架(3.2资源包)
spring-aspects-3.2.0.RELEASE.jar
AOP联盟规范(1个) (3.0.2依赖包)
com.springsource.org.aopalliance-1.0.0.jar
aspectJ支持(1个) (3.0.2依赖包)
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
制作目标对象
//目标对象类
public class UserService {
//连接点//切入点
public void add(){
//共性功能被抽取走了,放入到了MyAdvice类中的fn方法里
System.out.println("add");
}
//连接点
public void delete(){
System.out.println("bbbbbb");
System.out.println("delete");
}
}
制作通知
//通知类
public class MyAdvice {
//具有共性功能的方法:通知
public void fn(){
//共性功能
System.out.println("aaaaa");
}
}
开启AOP空间支持
xmlns:aop="http://www.springframework.org/schema/aop"


http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd


配置切面:切入点与通知之间的关系
<!-- 配置通知类为Bean -->
<bean id="myAdvice" class="cn.smile.aop.MyAdvice"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切面 -->
<!-- ref:对应的通知类的beanId -->
<aop:aspect ref="myAdvice">
<!-- 配置通知类别与关系(切入点与通知方法) -->
<!-- method:通知:共性功能 -->
<!-- pointcut:切入点:被挖走共性功能的方法 -->
<!-- aop:before:共性功能被挖走的位置 -->
<aop:before 
method="fn"
pointcut="execution(public void cn.smile.aop.UserService.add())"
/>
</aop:aspect>
</aop:config>
运行时必须使用Spring的格式(略)


切入点表达式
AOP切入点表达式支持多种形式的定义规则:
execution:匹配方法的执行(常用)
execution(public * *(..))
within:匹配包或子包中的方法(了解)
within(cn.smile.aop..*)
this:匹配实现接口的代理对象中的方法(了解)
this(cn.smile.aop.user.UserDAO)
target:匹配实现接口的目标对象中的方法(了解)
target(cn.smile.aop.user.UserDAO)
args:匹配参数格式符合标准的方法(了解)
args(int,int)

execution:表示执行某个切入点方法(常用)详细参看源码
格式:
“execution( [方法访问控制修饰符] 返回值类型 包名.类名.方法名(参数列表)) ”


切入点可以配置接口,运行时走实现类
切入点可以配置成公共的

<aop:config>
<!-- 声明切面间共享的切入点 -->
<aop:pointcut expression="execution(public void cn.smile.aop.UserService.add(*))" id="pt2"/>
<aop:aspect ref="myAdvice">
<!-- 声明切面内共享的切入点 -->
<aop:pointcut expression="execution(public void cn.smile.aop.UserService.add(*))" id="pt1"/>
<!-- pointcut-ref:引用公共切入点 -->
<aop:before pointcut-ref="pt2" method="fn"/>
<aop:before pointcut-ref="pt2" method="fn2"/>
</aop:aspect>
</aop:config>


通知类别
before:前置通知(应用:各种校验)
在方法执行前执行,如果其中抛出异常
after:后置通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
afterReturning:返回后通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,无法执行
afterThrowing:抛出异常后通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行
//环绕通知
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("around before......");
//调用原始方法
pjp.proceed();
System.out.println("around after......");
}


afterReturning和afterThrowing是不可能同时出现的


通知的配置格式
<aop:before pointcut-ref="pt2" method="before"/> 
<aop:after pointcut-ref="pt2" method="after"/> 
<aop:after-returning pointcut-ref="pt2" method="afterReturning"/> 
<aop:after-throwing pointcut-ref="pt2" method="afterThrowing"/> 
<aop:around pointcut-ref="pt2" method="around"/>

通知顺序:与配置顺序有关
 (有图解,如需要在详细了解,41-上-7-通知顺序)
多个切面间
先声明的before先运行,
后声明的before后运行
先声明的after后运行
后声明的after先运行
总结:配置时以最终运行顺序为准


总结:
AOP:关注共性功能的开发
共性功能抽出,运行时原始功能错误,必须加入共性功能,原始对象已经无法完成该功能,AOP代理负责 创建一个新的对象,该对象完成原始功能,通过织入操作完成。
Spring加载上下文时,会读取AOP的配置aop:config,Spring已经知道了哪些方法需要被监控,由切入点实现,当被监控的方法运行时,完成上面一段的操作,加入的功能需要根据配置完成。
织入:A模块中缺少B功能    BAA.class
编译期植入:A.class中对应的功能已经有BA
类加载期植入:A.class中不具有B功能,但是加载A.class时,内存中的类A.class具有B功能
运行期植入:执行到时,添加(Spring实现)


AOP通知参数
如果需要在通知方法中获取原始方法的调用参数,需要在通知方法的第一个形参位置声明JoinPoint类型的参数,使用该参数调用getArgs()方法可以获得原始方法的调用参数列表Object[]
public void before(JoinPoint jp){
Object[] objs = jp.getArgs();
System.out.println("before......"+objs[0]+","+objs[1]);
}
所有的通知类别均可获取原始方法调用参数

AOP通知返回值
只有afterReturning 与 around可以获取方法的返回值
afterReturning:在配置中设置returning属性,值是变量名的值,与方法的形参进行对应
<aop:after-returning  method="afterReturning" returning="abc"/>
public void afterReturning(JoinPoint jp,Object abc){
System.out.println("afterReturning......"+abc);
}
around:直接通过程序中的原始方法调用获取,该方法返回值即为原始方法的返回值
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("around before......");
//调用原始方法
Object obj = pjp.proceed();
System.out.println("around after......"+obj);
return obj;  说明:对原始方法拦截后,最终的运行返回值取决于这里
}

AOP切面
AOP切面描述的一组切入点与通知方法之间的绑定关系
一个AOP配置中,可以使用多个切面

AOP注解开发(重点)
开启AOP注解配置支持
将所有AOP过程中的资源配置成Bean(注解或者XML)
在通知对应的类上方声明@Aspect
在对应的方法上面声明通知类别,使用5种通知类别注解@Before
@Before仅仅定义了通知类别,需要为其指定切入点
@Before("execution(* cn.smile.aop.annotation.BookService.add(..))")
知识点一:注解开发公共切入点
//公共切入点配置
public class BookAdvice {
@Pointcut("execution(* cn.smile.aop.annotation.BookService.add(..))")
private void pt(){}
@Before("BookAdvice.pt()")... ...
知识点二:注解开发通知顺序以实际配置顺序为准
默认顺序(Spring 3.2.0的默认顺序):
around before
before
around after
after
afterReturning
知识点三:

代理模式
接口实现的对象——JDK动态代理——创建的是对象的代理对象
详细参看源码


非接口实现的对象——cglib动态代理——创建的是类的代理类,然后由代理类创建对象
CGLIB代理的不是对象,而是针对原始设计的类进行代理,产生一个被代理类的子类
Callback中的接口:
Dispatcher
FixedValue
InvocationHandler
LazyLoader
MethodInterceptor
NoOp
ProxyRefDispatcher

public class MyCglibProxyObject implements MethodInterceptor {
//提供一个方法用于创建Animal类的代理对象
public Animal createCglibProxyObject(){
//1.在内存中创建一个动态的类的字节码
Enhancer enhancer = new Enhancer();//此时并没有做继承
//2.为其指定父类
//除了完成继承关系外,还将父类所有的方法名反射过来,并在自己的类中创建了这些方法
enhancer.setSuperclass(Animal.class);
//3.指定其回调方法
enhancer.setCallback(this);
//4.使用该类创建对象
return (Animal) enhancer.create();
}

public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
System.out.println(proxy.getClass().getName());
if(method.getName().equals("eat")){
System.out.println("吃前来个开胃菜");
}
return methodProxy.invoke(proxy, args);
}
}

小结:
AOP:关注共性功能的开发,开发阶段可以不考虑书写共性功能,使用AOP配置后,就可以使原始功能在运行时将共性功能执行。
配置的方式两种:XML  注解
实际运行时动态代理出的对象在完成任务
对象的创建由Spring完成
如果原始对象没有实现接口——cglib
如果原始对象实现接口——Proxy

DAO模板类
JdbcTemplate类
jar包
Spring核心包(4个)
日志包(2个)
jdbc模板支持(1个)
spring-jdbc-3.2.0.RELEASE.jar
模板相关事务处理包(1个)
spring-tx-3.2.0.RELEASE.jar
ORM框架模板支持(1个)
spring-orm-3.2.0.RELEASE.jar
使用模板类
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//为其指定连接数据库的信息
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/springdb");
dataSource.setUsername("root");
dataSource.setPassword("root");
//使用模板类,必须先有一个模板类的对象,必须为其提供数据库相关的连接信息
JdbcTemplate template = new JdbcTemplate(dataSource);
//执行操作
template.execute("insert into tbl_user values(null,'jock',34)");
使用配置的格式将模板类转化为Bean
共有三种连接池配置方式
<!-- Spring自带的数据源对象 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- dbcp连接池 -->
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- c3p0 -->
<bean id="dataSource3" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
通过外部资源文件属性,引入数据
方式一:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"></property>
</bean>

方式二:
<context:property-placeholder location="*.properties"/>别忘了开启context命名空间
该方式会读取系统级属性System.getProperties();

默认系统级属性中有一个属性名叫做userName,它的值不可替代,是你的计算机名DAO支持抽象类


使数据层实现类继承DAO支持抽象类,提供了对应的获取模板对象的方法,默认给出了setter注入的方法
注意:数据层实现类一定要为其注入以下两种对象之一
模板对象:****Template
数据源:DataSource
获取模板对象:this.get****Template()
具体操作:参看源码事务管理


PlatformTransactionManager
事务管理器
TransactionDefinition
事务定义信息
TransactionStatus
事务具体运行状态事务管理方式(编程式)



编程式事务管理
声明式事务管理
XML:会配置,知道如何进行配置,不要求掌握配置的方式
注解:要求必须灵活应用
案例环境:银行转账业务A账户到B账户操作
表结构
CREATE TABLE `tbl_account` (
 `uuid` bigint(10) NOT NULL,
 `name` varchar(30) NOT NULL,
 `money` double(10,2) NOT NULL,
 PRIMARY KEY  (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tbl_account` VALUES ('1', 'tom', '1000.00');
INSERT INTO `tbl_account` VALUES ('2', 'jerry', '1000.00');
数据层制作接口与实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
public void inMoney(String in, Double money) {
String sql = "update tbl_account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql,money,in);
}


public void outMoney(String out, Double money) {
String sql = "update tbl_account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql,money,out);
}
}
业务层制作接口与实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String out, String in, Double money) {
//一个人减钱
accountDao.outMoney(out, money);
//一个人加钱
accountDao.inMoney(in, money);
}
}
配置对应的Bean
<!-- Service -->
<bean id="accountService" class="cn.itast.tx.account.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>

<!-- DAO -->
<bean id="accountDao" class="cn.itast.tx.account.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- DataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
环境搭建完毕
操作时,由于事务操作是开在数据层中的,当数据层中任意一个操作失败时,不能控制其他的操作回滚,造成了转账操作的错误,解决方案:必须将事务开启到业务层
流程:
在业务层使用事务模板对象,该对象可以将多个业务封装到同一个事务中
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(final String out,final  String in,final  Double money) {
TransactionCallback tc = new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
//在当前方法中运行的所有操作处于同一个事务
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
};
//事务管理操作
transactionTemplate.execute(tc);
}
业务层Bean注入事务管理模板
<bean id="accountService" class="cn.itast.tx.account.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
声明一个事务管理模板Bean,该Bean依赖与事务管理器对象
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
声明一个事务管理器的Bean,该Bean依赖与DataSource运行,该DataSource必须与数据层操作注入的DataSource相同
<bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>事务管理方式(XML声明式)



所谓声明式事务管理就是将编程式事务管理中的代码抽取成AOP的通知(环绕通知),然后使用AOP的思想将事务管理的代码在运行时织入到原始业务逻辑操作中

必须声明事务管理的通知,该通知由Spring完成,只需要进行配置, 
<!-- AOP:通知类 Spring制作的,通过tx命名空间开启 -->
<!-- 需要为其指定对应的事务管理器的Bean-->
<tx:advice id="txManager" transaction-manager=" transactionManager ">
<!-- 配置事务属性 -->
<tx:attributes>
<!-- 为所有的transfer方法添加事务 -->
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
注意:
必须开启tx命名空间
需要为其指定事务管理器
<!-- 定义事务管理器的Bean -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
配置AOP,将要添加事务管理的操作配置AOP
<!-- AOP:config -->
<aop:config>
<aop:advisor advice-ref="txManager" 
pointcut="execution(* cn.itast.tx.account.AccountService.transfer(..))"/>
</aop:config>
注意:引用Spring定义的事务通知,需要使用aop:advisor元素,而不是aspect
method的参数
参数名 实例作用
name name=“get*”定义参与事务管理的方法,支持通配符
timeout  timeout=-1 定义事务超时时间,-1为永不超时
read-only  read-only=“false” 定义事务种类为只读事务或读写事务
no-rollback-for异常名称 定义不参与事务回滚的异常名
rollback-for  异常名称 定义参与事务回滚的异常名
isolation  Isolation 定义事务隔离级
propagation  propagation 定义事务的传播属性
propagation
事务传播行为修饰的是事务协调员对事务管理者所携带的事务的一种态度
事务传播行为  事务管理者 事务协调员
REQUIRED  T1 T1
                            无           T2
REQUIRES_NEW  T1 T2
                            无 T2
SUPPORTS            T1          T1
                            无           无
NOT_SUPPORTED  T1 无
                            无 无
MANATORY          T1          T1
                            无        ERROR
NEVER T1ERROR

                            无 OK

NESTED 嵌套事务

案例:
程序中对象的uuid不是由数据库自动生成,变成由另一个操作完成,使用另一个表保存uuid值
User   1()2 1 2  2 34 5
4
Tbl_uuid
User 3事务管理方式(注解声明式)



为需要添加事务的类或接口或方法上方添加@Transactional
@Transactional
public interface AccountService {...}
配置中声明使用注解式事务管理
<!-- 开启注解式事务管理功能 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
注意:该配置需要依赖一个事务管理器的对象
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
开发中一般使用:
业务层接口上方声明注解式事务@Transactional
配置中开启注解式事务管理