spring 总结

Spring 总结:

主要从讲述以下几个知识点:
目录结构:
1,Spring 概述

	1.1 Spring 的主要作用:
	1.2 Spring 的核心是控制反转(IOC)和 面向切面编程(AOP

2,Spring 与 IOC

	2.1 IoC的定义
	2.2 创建容器
	2.3 ApplicationContext 与 BeanFactory 容器的区别
	2.4 Bean 的装配
	2.5 容器中 Bean 的作用域
	2.6 Bean 的后处理器
	2.7 Bean 的生命周期
	2.8 <bean /> 标签的 id 属性与 name 属性(了解即可)
	2.9 基于 XMLDI
	2.10  基于注解的 DI
	2.11 注解 与 XML 共同使用

3,Spring 与 AOP

	3.1 AOP概述
	3.2 通知 Advice(spring 框架自己实现的 AOP3.3 顾问 Advisor(spring 框架自己实现的 AOP3.4 自动代理生成器
	3.5 AspectJ 框架对 AOP 的实现(重点)

4,Spring 与 DAO

	4.1 Spring 与 JDBC 模板(对 IOC 的应用)
	4.2 从属性文件读取数据库连接信息
	4.3  配置 JDBC 模板
	4.4  Dao 实现类继承 jdbcDaoSupport

正文:

1,Spring 概述
Spring 是一个容器,用于降低代码之间的耦合度,根据不同的代码采用 IOC 和 AOP 两种技术来解耦合

1.1 Spring 的主要作用:

	是为代码“解耦”,降低代码间的耦合度。
	可以管理对象的生命周期、对象与对象之间的依赖关系。可以通过配置文件,来定义对象,以及设置与其他对象的依赖关系。

1.2 Spring 的核心是控制反转(IOC)和 面向切面编程(AOP)

根据功能的不同,可以将一个系统中的代码分为,主业务逻辑与系统级业务逻辑两类。
	主业务逻辑:
		主业务逻辑代码间逻辑联系紧密,有具体的专业业务应用场景,复用性相对比较低
	系统级业务:(交叉业务)
		系统级业务相对功能独立,没有具体的专业业务应用场景,主要是为主业务提供系统级服务,如日志、安全、事物等,复用性强。
		Spring 根据代码的功能特点,将降低耦合度的方式分为了两类:IOCAOPIOC 使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是有 Spring 容器统一管理,自动“注入”。

2,Spring 与 IOC

2.1 IoC的定义

控制反转(IoC,Inversion of Control),是一个概念,是一种思想。指将传统上有程序代码直接操控的对象调用权交给容器,通过容器来实现
	   对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。
	IoC 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种:依赖注入和依赖查找。依赖注入应用更为广泛。
	依赖查找:
		Dependency Lookup,DL,容器提供调用接口和上下文环境给组件,程序代码则需要提供具体的查找方式。比较典型的是依赖于 JNDI 服务
		接口的查找
	依赖注入:
		Dependency Injection,DI,程序代码不做定位查询,这些工作容器自行完成。
		依赖注入是目前最优秀的解耦方式。

2.2 创建容器

ApplicationContext ac = null
	方式1:(在类路径下(src下)找配置文件)
		ac = new ClassPathXmlApplicationContext"applicationContext.xml");
	方式2:(在项目根路径下找配置文件,或盘符下)
		ac = new FileSystemXmlApplicationContext("applicationContext.xml")

2.3 ApplicationContext 与 BeanFactory 容器的区别:

这两个容器对于其中创建 Bean 的时机不同,通常是使用 ApplicationContext 容器
	1,ApplicationContext 容器在进行初始化时,会将其中的所有Bean(对象)进行创建
		缺点:占用系统资源(内存、CPU等)
		优点:响应速度快
	2,BeanFactory容器中的对象,在容器初始化时不会创建,而是在真正获取该对象时才被创建
		缺点:相对来说,响应速度慢
		优点:不多占用系统资源
	
	一个空的对象,占 8 个字节。
	在执行无参构造方法执行时,已经完成了给对象在内存的堆中分配好了空间,并且已经给成员变量做完了初始化赋值工作。
	在执行无参构造方法之前先执行了动态代码块

2.4 Bean 的装配

即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配
	1,默认的装配方式:
		代码通过 getBean()方法从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参构造器,创建空值的实例对象。
		注:当需要通过spring来获取 bean 对象时,这个类给出了带参构造器后一定要记得定义一个无参构造器,原因是底层使用的反射机制,在反射机制中用到了无参构造器

	2,动态工厂 Bean
		<bean  id="factory"  class="com.shz.ServiceFactory" />
		<bean  id="myService"  factory-bean="factory"  factory-method="getMyService" />

	3,静态工厂 Bean
		静态工厂是不需要创建对象的,直接通过类名点
		<bean  id="myService"  class="com.hsz.ServiceFactory"  factory-method="getMyService" />

2.5 容器中 Bean 的作用域

	1,单例模式:只在容器中创建一个对象,每次获取的都是同一个对象
		其对象的创建 时机 是在 Spring容器初始化时创建的,是默认值。
		<bean  id="myService"  class="com.hsz.SomeServiceImpl"  scope="singleton" />
	2,原型模式:其对象的创建时机不是在 Spring容器初始化时创建,而是在代码中真正访问时才创建
		<bean d="myService"  class="com.hsz.SomeServiceImpl"  scope="prototype" />
		不常用的两个作用域
	3,request:对于每次http请求,都将会产生一个一个不同的<bean />
	4,session:对于每一个不同的HTTP session,都将会产生一个不同的 bean 实例

2.6 Bean 的后处理器

	1,实现 BeanPostProcessor 接口
	2,注册 bean 后处理器
		没有 id
		<bean  class="com.hsz.MyBeanPostProcessor" />
	3,实现接口中的方法
		public Object  postProcessBeforeInitialization(Object bean,String  beanName){}
		public Object  postProcessAfterInittialization(Object bean,String beanName){}
		bean:表示当前正在进行初始化的 Bean 对象
		beanName:表示当前正在进行初始化的 Bean 对象的 id
	4,在 after 方法中使用 JDK 自带的 proxy 动态代理来给代码做增强处理

2.7 Bean 的生命周期

	1,定制 Bean 的生命周期始末
		<bean  id="myService"  class="xxx"  init-method="setUp"  destroy-method="teamDown" />
		init-mothod:对应的方法是在无参构造方法执行完后就执行的方法
		destroy-method:在 bean 销毁之前,执行的方法
		执行这个方法是有条件的:
			1)当前的Bean需要是singleton的
			2)要手工关闭容器(关闭时使用实现类的 close 方法来关闭)
	2

2.8 标签的 id 属性与 name 属性(了解即可)

	id 的命名需要满足 xml 对 id 属性命名规范:必须以字母开头,可以以字母开头,可以包含字母、数字、句号、冒号(新版本的spring可以使用 /)
	name 属性值则可以包含各种字符

2.9 基于 XML 的 DI

1,注入的分类:
1)设值注入(比较常用)
		在 applicationContext.xml 中
		<bean  id="myStudent"  class="com.hsz.MyStudent">
			<property name="name"  value="张三">
			<property name="age"  value="18">
			<property name="shool"  ref="myShool">
		</bean>
		在对应类中定义对应的属性及 set 方法
		底层原理是通过反射机制,找到set方法进行赋值的
2)构造注入
	方式一:使用索引
		<bean  id="myStudent"  class="com.hsz.MyStudent">
			<constructor index="0"  value="张三">
			<constructor index="1"  value="18">
			<constructor index="2"  ref="myShool">
		</bean>
		index对应的是对应类的带参构造的顺序,和属性的 set 方法无关。
	方式二:使用 name 属性
		<bean  id="myStudent"  class="com.hsz.MyStudent">
			<constructor name="name"  value="张三">
			<constructor name="age"  value="18">
			<constructorname="shool"  ref="myShool">
		</bean>
2,命名空间注入(了解即可)
分类:P命名空间注入,C命名空间注入
			在使用之前需要事先添加对应的头部 约束声明
		1P命名空间注入:
			<bean  id="myStudent"  class="com.hsz.Shool"  p:name="清华大学"/>
			底层调用的还是 set 方法注入
		2C命名空间注入:
			<bean  id="myStudent"  class="com.hsz.MyStudent"  c:name="张三"  c:age="18"/>
			在对应的类中都没有无参构造器也可以,在底层中直接调用的是带参构造器。
			经验:只要加了带参构造,都加上无参构造器。
		3)实现特定接口注入
			这种方式采用侵入式编程,污染了代码,所以几乎不用。
3,集合属性注入
	array
	list
	set
	map
	property
	方式一:传统的写法
		<bean  id="mySome"  class="com.hsz.MySome">
			<property  name="shools">
				<array>
					<ref bean="mySchool" />
					<ref bean="myShool2" />
				</array>
			</property>
			<property  name="shools">
				<list>
					<value >篮球 </value>
					<value >足球 </value>
				</list>
			</property>
			。。。。。。。。。
		</bean>
	方式二:比较简单的方式
		使用 value 属性,中间用逗号分开即可,但是只能在 数组,list,set 中使用
		<bean  id="mySome"  class="com.hsz.MySome">
			<property  name="myList" value="篮球,足球">
			。。。。。。
		</bean>
		注:Map 和 property 中的 key 和 value 之间的区别
		Map:key 和 value 是 obejct 类型
		property:中的 key 和 value 只能是 String 类型
4,对于域属性的自动注入
	1)byName
		<bean  id="mySome"  class="com.hsz.MySome"  autowire="byName">
			<property name="name"  value="张三">
			<property name="age"  value="18">
		</bean>
		会自动在容器中查找与实体类的域属性同名的 bean 的 id,并将该 bean 的属性赋值给该域属性
	2)byType
		<bean  id="mySome"  class="com.hsz.MySome"  autowire="byType">
			<property name="name"  value="张三">
			<property name="age"  value="18">
		</bean>
		会自动在容器中查找与实体类的域属性具有 is - a关系的 bean,并将该 bean 的属性赋值给
5,使用SPEL注入
	Spring 的 EL 表达式
	作用:
		1)可以使用 JavaEE 中的静态方法 #{ T(java.lang.Math).random() * 50  }
		2)可以调用其他 bean 的属性,方法
		3)可以在 表达式中进行计算
			<bean  id="mySome"  class="com.hsz.MySome"  autowire="byType">
				<property name="name"  value="#{ myPerson.pname }">
				<property name="age"  value="#{ myPerson.score > 25 ? 25 : myPerson.score}">
				<property name="score"  value="#{ myPerson.scoreAvg()}">
			</bean>
	myPerson 是一个 bean 的 id,pname 和 score 是其属性,scoreAvg()是其方法,给mySome 中的属性注入值
6,使用内部 Bean注入(了解即可)
7,使用同类抽象 Bean 注入(了解即可)
	和 继承差不多,父类定义成 abstract
8,使用异类抽象 Bean 注入(了解即可)
9,位应用指定多个 Spring 配置文件(了解即可)
	1)在读取配置文件时,以可变长参数 或 数组来传入配置文件 来解析
	2)使用通配符

2.10 基于注解的 DI

要使用注解开发,需要在 Spring 的配置文件中定义,注解扫描器
注解的注入方式 和 set 方法没有关系,和 xml 的实现方式不一样。
1,定义 Bean @Compinent  组件
	1)在一个类的上方添加 @Compinent 注解,表示当前类被 Spring 容器所管理
	2)给这个类的属性赋值:
		在属性的上方添加 @Value("xxx"3)与@Component 注解功能相同,但意义不同的注解还有三个:
		1,@Repository:注解在Dao实现类上
		2,@Service:注解在Service实现类上
		3,@Controller:注解在 SpringMVC 的处理器上
2,Bean 的作用域 @Scope
	@Scope("")

3,基本类型注入域属性 @Value

4,按类型注入域属性 @Autowired
	 byType 方式的注解式注入,根据在 配置文件中的指定要扫描的包下,找这个类型的类并创建。

5,按名称注入域属性 @Autowired 与 @Qualifier
	需要在对应的 注解中事先取一个名字

6,域属性注解 @Resource
	JSR-250 规范要求,要求 JDK 要在1.6 以上
	@Resource     byType 方式注入
	@Resource(name="xxx")     byName  方式注入
7,Bean 的生命始末 @PostConstruct 与 @PreDestroy
	 //  了解即可

8,使用 JavaConfig 进行配置(了解即可)
	在类的上方添加 @Configuration 注解
	表示当前类充当 Spring 容器,即所有的 Bean 将由这个类来创建

9,使用Spring 的 Junit4 测试 Spring
	在测试类的上方添加注解
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration(locations="classpath:com.hsz.applicationContext.xml")
	Public class MyTest{
		@Aotuwired
		private Student  student;
		
		@Test
		public void test01(){
			System.out.println(student);
		}
	}

2.11 注解 与 XML 共同使用

	XML 的优先级要高于 注解,原因是:对于程序的发布,和维护方便,不需要重新编译。
	经验:即使是使用注解式开发,最好也保留属性的 set 方法。

3,Spring 与 AOP
3.1 AOP概述

	1AOP 面向切面编程,是面向对象编程 OOP 的一种补充。面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序
		运行过程。
		AOP 底层,就是采用动态代理模式实现的。采用了两种代理:JDK的动态代理,与 CGLIB 的动态代理。
		主要是把通用的与主业务逻辑无关的代码,如安全检查、事务、日志等织入到主业务逻辑代码中。
	2AOP编程术语
		切面(Aspect):
		织入:
		连接点:
		切入点:
		被标记为 final 的方法是不能作为连接点和切入点的。因为最终的是不能被修改的,不能被增强的。
		目标对象:
		通知:
		顾问:
	3AOP 编程环境搭建

3.2 通知 Advice(spring 框架自己实现的 AOP)

	缺点:通知只能指定增强的时机,即增强的,不能指定切入点。
	1,前置增强
		需要 代理类 实现 MethodBeforeAdvice 接口
		使用 ProxyFactoryBean 实现
	2,后置增强
		需要 代理类 实现 AfterReturningAdvice 接口 
		可以获得目标方法的返回结果,但是无法改变目标方法的结果。 
	3,环绕增强
		需要 代理类 实现 MethodInterceptor 接口 
	4,异常增强 
		需要目标类实现 ThrowsAdvice 接口 
		try。。。catch 和 throws 的区别:
		1,发生在 try。。。catch。。。 中的异常不会往外抛,如果是使用 Junit 进行测试的话,就算是出现异常,结果都是绿条,但是在
		   控制台中会打印出异常信息
		2,异常通过 throws 抛出去后,如果发生异常,Junit 的结果是红条,但是在控制台中不会打印异常信息。因为当前异常已经被抛出去了,
		   当前类不知道有异常的发生。

3.3 顾问 Advisor(spring 框架自己实现的 AOP)

	1,方法名称匹配切入点顾问
		匹配的对象时简单方法名
	2,使用正则表达式方法切入点顾问
		<bean id = "myAdvisor"  class = "org.springframework.aop.RegexpMethodPoincutAdvisor">
			<property  name = "advice" ref = "myAdvice" />
			这里得的正则表达式匹配的对象是  权限定性方法名,不包括方法名的小括号
			<!-- <property name = "pattern"  value = ".*doFirst" />  -->
			<!-- <property name = "patterns"  value = ".*doFirst,.*doSecond" />  -->
			<!-- <property name = "pattern"  value = ".*doFirst | .*doSecond" />  -->
			<!-- <property name = "pattern"  value = ".*S.*" />  -->
		</ bean>
	
	当前代码存在的两个问题:
		1,若存在多个目标对象,就需要使用多次 ProxyFactoryBean 来创建多个代理对象,这会使配置文件变得臃肿,不便于管理
		2,用户真正想调用的是目标对象,而真正可以调用的却是代理对象,这不符合正常的逻辑
		以上这两个问题,均为 ProxyFactoryBean 类的功能太简单引起的

3.4 自动代理生成器

	1,默认代理 advisor 自动代理生成器
		注册自动代理生成器
		<bean  class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
		在使用时,直接用目标对象,底层代码实现了 BeanPostProcessor 接口(bean 后处理器接口)
		存在三个问题:
			1)不能选择目标对象
			2)不能选择切面类型,切面只能是advisor
			3)因为不能选择advisor,所以advisor均将被作为切面织入到目标方法
	
	2,Bean 名称自动代理生成器
		注册自动代理生成器
		<bean  class = "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
			<property  name = "beanNames"  value = "someService" />
			<property  name = "interceptorNames"  value = "myAdvice" />
		</bean>

3.5 AspectJ 框架对 AOP 的实现(重点)

	1,AspectJ概述
		对于 AOP 这种编程思想,很多框架都进行了实现。spring就是其中之一,可以完成面向切面编程,然而,AspectJ 也实现了 AOP 的功能,
		也是一个比较小的框架,且实现方式更为简捷,使用更为方便,而且还支持注解式开发。所以,spring 又将 AspectJ 的对于 AOP 的实现
		也引入到了自己的框架中。
		在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。
	
	2,Aspectj的通知类型
		前置通知:
		后置通知:
		环绕通知:
		异常通知:
		最终通知:
	
	3,AspectJ 的切入点表达式
		表达式原型:
		execution([modifiwes-pattern] 访问权限类型  
		ret-type-pattern  返回值类型
		[declaring(param-pattern)] 全限定性类名
		name-pattern(param-pattern)  方法名(参数名)
		[throws-pattern]  抛出异常类型 )
		符号:
			*0至多个任意字符
			..  :用在方法参数中,表示任意多个参数用在包名后,表示当前包及其子包路径
			+ :用在类名后,表示当前类及其子类
			用在接口后,表示当前接口及其实现类
			用的比较常用的表达式:
			execution(* *..service.*.*(..))
			指定所有包下的 service 子包下所有类(接口)中所有方法为切入点
			execution(* *..service.*(..))
			指定所有包下的 service 接口中所有方法为切入点

3.4 Aspectj 基于注解的 AOP 实现(不常用)

	使用步骤:
	1)在一个类的上方添加 @Aspect 注解,表示当前类为切面
	2)在 xml 文件中注册 这个类
	3)定义目标类,即需要增强的类
	4)在这个类中定义相应的方法上方添加对应的注解,如:
		前置通知:
			@Before("execution(* *..ISomeService.doFirst(..))"public void MyBefore(JoinPoint  jp){
				// 入参的是具体的与表达式匹配的执行的目标类的权限定性方法名 和返回值
			}
		后置通知:
			@AfterReturning(value = "execution(* *..ISomeService.doSecond(..))",returning = "result"public void myAfterReturning(Object result){
				// result 就是执行方法后的返回值,但是没有返回值。 
			}
		环绕通知:
			@Around("execution(* *..ISomeService.doFirst(..))"public Object myAround(ProceedingJoinPoint  pjp){
				Object  result = pjp.proceed()// 执行方法,这里需要进行一场处理
				return result; // 可以修改返回值
			}
		异常通知:
		@AfterThrowing(value = "execution(* *..ISomeService.doFirst(..), throwing = "ex")"public void myAfterThrowing(Exception ex){
			// 表达式中的 throwing 可以指定也可以不指定,即可以指定异常类型
		}
		最终通知:
		@After("execution(* *..ISomeService.doFirst(..))"// 定义一个切入点,叫 doThirdPointcut(),上面的表达式都可以换成这个名字
		@Pointcut("execution(* *..ISomeService.doFirst(..))"public void doThirdPointcut(){}
	
	5)在 spring 的注配置文件中注册 AspectJ 的自动代理
		<aop:aspectj-autoproxy />

3.5 Aspectj 基于XML 的 AOP 实现

实现步骤:
1)定义一个增强类
2)定义一个需要被增强的类
3)配置 spring 的主配置文件
	<aop:config>
		<aop:pointcut  expression = "execution(* *..ISomeService.doFirst(..))"  id="doFirstPointcut">
		<aop:pointcut  expression = "execution(* *..ISomeService.doFirst(..))"  id="doSecondPointcut">
		<aop:pointcut  expression = "execution(* *..ISomeService.doFirst(..))"  id="doThirdPointcut">    // 切入点可以定义多个
		
		<aop:aspect  ref = "myAspct">     // 注意这里不是用 id
			<aop:before method = "myBefore"  pointcut = "execution(* *..ISomeService.doFirst(..))" />   // 表达式的方式一     
			<aop:before  method = "myBefore(org.aspect.lang.JoinPoint)"  pointcut-ref = "doFirstPointcut">    //  使用表达式的方式二       // 前置增强
			<aop:after  " method = "myBefore(org.aspect.lang.JoinPoint)"  pointcut-ref = "doFirstPointcut"  returning = "result">    // 后置增强
			<aop:after-throwing  method = "myAfterThrowing"  pointcut-ref = "doThirdPointcut"  throwing = "ex">    // 异常增强
			<aop:after  method="doThirdPointcut">
		</aop:aspect>
	</aop:config>

4,Spring 与 DAO
4.1 Spring 与 JDBC 模板(对 IOC 的应用)

JDBC 模板也是一个框架,也可以对数据库进行增删改查操作,只是这个框架太小了,所以一般不叫它框架。
1,数据源的配置
	数据源有三种:
	1)Spring 默认的数据源(内置的连接池) DriverManagerDataSource
		<bean  id = "myDataSource"  class = "org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name = "driverClassName"  value="com.mysql.jdbc.Driver">
			<property name = "url"  value="jdbc:mysql://127.0.0.0:3306/test">
			<property name = "userName"  value="root">
			<property name = "password"  value="111">
		</bean>
	2DBCP 数据源 BasicDataSource
		<bean  id = "myDataSource"  class = "org.springframework.jdbc.datasource.BasicDataSource">
			<property name = "driverClassName"  value="com.mysql.jdbc.Driver">
			<property name = "url"  value="jdbc:mysql://127.0.0.0:3306/test">
			<property name = "userName"  value="root">
			<property name = "password"  value="111">
		</bean>
	3C3P0 数据源 ComboPooledDataSource
	<bean  id = "myDataSource"  class = "org.springframework.jdbc.datasource.ComboPooledDataSource">
	<property name = "driverClass"  value="com.mysql.jdbc.Driver">
	<property name = "jdbcUrl"  value="jdbc:mysql://127.0.0.0:3306/test">
	<property name = "user"  value="root">
	<property name = "password"  value="111">
	</bean>
	数据库连接池:
	连接池中的连接的创建时机是,应用一启动就先创建好。
		1,设置初始创建 连接 数量
		2,设置 连接下限 数量
		当连接池中的连接数量剩余的数量低于这个数量时,再次创建连接
		3,设置一次创建的连接数量
		低于连接下限的时候一次创建的连接数量
		4,设置连接池中的连接上限
		回收连接时的最大数量,当回收的连接数超过这个数量,就会释放超出的连接
		5,设置最大空闲连接数
		数据库中的连接一直没有被使用,只保留的在连接池中的连接数
		6,设置最大空闲时间

4.2 从属性文件读取数据库连接信息

1<bean/> 方式(不常用)
	使用class 为PropertyPlaceholderConfigurer
	eg:
		<bean class = "org.springframewrk.beans.factory.config.PropertyPlaceholderConfigurer">
			<property  name = "location" value = "classpath:jdbc.properties" />
		</bena>
2<context:property-placeholder>  (常用)
	1,引入 context 约束
	2<context:property-placeholder location="classpath:jdbc.properties"/>  

4.3 配置 JDBC 模板

JDBC 模板,注入到 Dao 中
方式一:
	注册 jdbcTemplate
	<bean  id = "myJdbcTemplate"  class = "org.springframework.jdbc.core.JdbcTemplate">
		<property  name = "dataSource"  ref = "myDataSource" />
	</bean>
	注册 Dao
	<bean id = "studetnDao"  class = "com.hsz.dao.StudentDaoImpl">
		<property  name = "jdbcTemplate"  ref = "myJdbcTemplate" />
	</bean>
方式二:
	注册 Dao,直接把数据源注册到 Dao 中,底层源码会自动注入
	<bean id = "studetnDao"  class = "com.hsz.dao.StudentDaoImpl">
		<property  name = "dataSource"  ref = "myDataSource" />
	</bean>
	注册 Service
	<bean  id = "studentService"  class = "com.hsz.service.StudentServiceImpl">
		<property  name = "dao"  ref = "studnetDao"/>
	</bean>

4.4 Dao 实现类继承 jdbcDaoSupport

继承之后,可以通过 get.JdbcTemplate() 方法获得模板,然后通过调用模板的 update 方法(增删改都是使用 update 方法,和 mybatis 的底层原理一样),和 query 方法
eg: SQL 语句使用 ? 作为 占位符
	public void insertStudent(Student student){
		String sql = "insert into studnet(name,age) values(?,?)"this.getJdbcTemplate().update(sql,student.getName(),studnet.getAge())}
	// 查询所有学生的名字,String.class 是指定返回类型
	public void selectAllStudentsNames(){
		String sql = "select name from studnet"this.getJdbcTemplate().queryForList(sql,String.class)}
	// 查询单个学生的名字
	public void selectAllStudentsNames(){
		String sql = "select name from studnet where id = ?this.getJdbcTemplate().queryForObject(sql,String.class,id)}

// 查询所有学生的信息,返回的是学生对象的集合
注:因为 jdbc 模板这个框架功能过于简单,所以需要自己手动进行封装对象。
①,定义一个实现 RowMapper 接口的类
public class StudentRowMapper implements RowMapper<Student>{
	// rs:当查询出总的结果集后,框架会自动遍历这个结果集,每次遍历的一行数据,都会被存放到这个方法的 rs 参数中。也就是说,这里的 rs 代表的是一行数据,并非所有的查询结果。换一个角度来说,只要能执行到这个方法,就说明这里的 rs 不会是空的。
	public Student mapRow(ResultSet rs,int rowNum) throws SQLException{
		Student student = new Studnet();
		student.setId(rs.getInt("id"));
		studnet.setName(rs.getString("name"));
		studnet.setAge(rs.getInt("age"))return student;
	}
}
②,
public Studnet selectAllStudnts(){
	String sql = "select id,name,age  from studnet;
	this.getJdbcTemplate().query(sql,new StudentRowMapper())}

5,注意:JDBC 模板对象是多例的
jdbcTemplate 对象时多例的,即系统会为每一个使用模板对象的线程(方法)创建一个 jdbcTemplate 实例,并且在该线程(方法)结束时,自动释放 jdbcTemplate 实例。所以在每次使用 jdbcTemplate 对象时,都需要通过 getJdbcTemplate()方法获取。

2)Spring 的事务管理(对 AOP ,IOC 的应用)

1,spring 事务管理的概述 及 API:

1)事务原本是数据库中的概念,在 Dao 层中,但一般情况下,需要经事务提升到 业务层。这样做事为了能够使用事务的特殊性来管理具体的业务。
2)事务管理器接口
	PlatformTransactionManager 接口对象。其主要作用是用于完成事务的提交,回滚,及获取事务的状态信息。
	常用的两个实现类:
	DataSourceTransactionManager:使用JDBC 或 iBatis 进行持久化数据时使用
	HibernateTransactionManager:使用 Hibernate 进行持久化数据时使用
	Spring 的默认回滚方式是:发生运行时异常时回滚,发生受查时异常时提交。不过,对于受查异常,程序员也可以手动设置其回滚方式。
3)事务定义接口
	事务的隔离级别: 
	trnasaction_default				默认的隔离级别根据不同数据库自动选择
	transaction_none       			0
	transaction_read_committed		2	oracle 的事务隔离级别
	transaction_read_uncommited	1
	transaction_repeatable_read		4	MySQL的事务隔离级别
	transaction_serializable			8

事务的传播行为:

如:a 方法在 a 事务下运行,b 方法在 b 事务下运行。当 a 方法调用 b 方法时,b 方法运行的是哪一个事务环境下运行?
	
① REQUIRED  默认的
指定的方法必须在事务内执行。若当前存在事务,就加入到当前的事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。
如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther()方法时就是在事务内运行的,则 doOther()方法的执行也
加入到该事务内执行。若 doSome()方法在调用 doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。
 
 ② REQUIRES_NEW
总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
 
 ③ SUPPPORTS
指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。

④ NOT_SUPPORTED
指定的方法不能再事务环境中执行,若当前存在事务,就将当前事务挂起。

⑤ NESTED
指定的方法必须在事务内执行。若当前存在事务,则在嵌套事务内执行;若当前没有事务,则创建一个新事务。
定义了默认事务超时时限,一般是使用默认的设置值。

⑥MANDATORY
指定的方法必须在当前事务内执行,若当前没有事务,则直接抛出异常。

⑦ NEVER
指定的方法不能在事务环境下执行,若当前存在事务,就直接抛出异常。

在Spring 中通常可以通过以下三种方式来实现对事务的管理:
2,使用 spring 的事务代理工厂管理事务(了解即可)

使用 JDBC 模板的时候,使用的事务管理
缺点:配置文件容易臃肿,在测试类中使用的是代理类
注册事务管理器
<bean  id = "myTransactionManager"  class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property  name = "dataSource"  ref = "myDataSource" />
</bean>
	// 生成事务代理对象
<bean  id = "serviceProxy"  class  = "org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	<property name = "transactionManager"  ref = "myTransactionManager" />
	<property name = "target"  ref  ="buyStockService" />
	<property  name = "transactionAttributes">
	<props>
		<prop key = "open*">ISOLATION_DEFAULTPROPAGATION_REQUIRED</prop>
		//  -异常:表示发生指定异常后回滚,这时的异常通常是受查时异常
		// +异常:表示发生指定异常后提交,这时的异常通常是运行时异常
		<prop key = "buyStock*">ISOLATION_DEFAULTPROPAGATION_REQUIRED-BuyStockException</prop>
		</props>
	</property>
</bean>

3,使用 Spring 的事务注解管理事务

1)生成事务注解对象
<bean  id = "myTransactionManager"  class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property  name = "dataSource"  ref = "myDataSource" />
</bean>
2)注册事务注解驱动
需要加 tx 约束
<tx:annotation-driven  transaction-manager = "myTransactionManager" />
3)在 service 层中对应的方法上方添加 事务 注解
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=BuyStockException.class)
public void buyStock(String aname,double money,String sname,int amount) throws Exception{
boolean  isBuy = true;
adao.updateAccount(aname,money,isBuy)if(1 == 1){     // 临时定义的异常
throw new BuyStockException("购买股票异常")}
sdao.updateStock(sname,amount,isBuy)}

4,使用 AspectJ 的 AOP 配置管理事务
1)生成事务注解对象
<bean  id = "myTransactionManager"  class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property  name = "dataSource"  ref = "myDataSource" />
</bean>
2AOP 配置
注册事务通知,这里指定的是为每一个连接点指定所要应用的事务属性
<tx:advice  id = "txAdvice"  transaction-manager="myTransactionManager">
<tx:attributes>
<tx:method  name="open*"  isolation="DEFAULT"  propagation="REQUIRED" />
<tx:method  name="buyStock"  isolation="DEFAULT"  propagation="REQUIRED"  rollback="BuyStockException">
<tx:attributes>
<tx:advice>

<aop:config>
这里指定的是切入点,没有具体指定方法,当指定方法时,上面的通知就不起作用了,但是一般都在通知中具体配置
<aop:pointcut  expression="execution(* *..service.*.*(..))"  id="myPointcut">
<aop:advisor  advice-ref="txAdvice"  pointcut-ref="myPointcut">
</aop:config>

5,Spring 与 MyBatis 整合

就是要把 mybatis 的 sqlSessionFactoryBean 交给 spring 来管理
1)Mapper动态代理方式(这种方式不常用,配置文件过于臃肿)
<bean  id = "mySqlSessionFactory"  class = "org.mybatis.spring.SqlSessionFactoryBean">
	<property  name = "configLocation"  value = "classpath:mybatis.xml">
	<property  name = "dataSource"  value = "myDataSource">
</bean>
针对某一个 Dao 而生成的代理对象
<bean  id = "studnetDao"  class = "org.mybatis.spring.mapper.MapperFaactoryBean">
	<property  name = "sqlSessionFactory"  ref = "mySqlSessionFactory" />
	<property  name = "mapperInterface"  value = "com.hsz.dao.IstudentDao">
</bean>
注册 Service
<bean  id = "studentService"  class ="com.hsz.service.StudentServiceImpl">
	<properyt  name = "dao"  ref ="studentDao" />
</bean>
2)支持扫描的 Mapper 动态代理
// 以下配置会为指定的基本包中所有的接口生成代理对象
<bean  class = "org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property  name = "sqlSessionFactoryBeanName"  value = "mySessionFactory" />
	<property  name = "basePackage"  value = "com.hsz.dao" />
</bean>
// 注册 service
<bean  id = "studentService"  class = "com.hsz.service.StudentServiceImpl">
	// 这里的 Dao 接口的注入需要使用 ref 属性,
	// 若 Dao 的接口名的前两个字母是大写,则这里的值为接口的简单类名
	// 若 Dao 的接口名的首字母是大写,第二个字母为小写,则这里的值为简单类名,但首字母要小写 
</bean>

6,Spring 与 Web

目的:是为了让 spring 容器的生命周期 和 整个应用的生命周期一致,并且                                                                            使创建的 spring 容器是单例的(因为 spring 容器在创建完后,会创建容器中所有的对象实例,如果不是单例的话,就会创建大量的对象,浪费内容),所以把创建 spring 容器的这个工作交给 web 容器来完成。 
1)在 web.xml 配置文件中注册 ServletContext监听器,完成两件工作
	① 在 ServletContext 被创建时,创建 Spring 容器对象
	② 将创建好的 Spring 容器对象放入到 ServletContext 的域属性空间
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
2)配置 <context-param>
	指定 spring 配置文件的位置及名称,如果不进行指定只能放在 WEB-INF 目录下
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
3)使用工具类获取 Spring 容器
	WebApplicationContext  ac  = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值