Spring精讲课程

Spring4 框架技术讲义
Spring精讲课程
第1章 Spring 概述
1.1 为什么使用 Spring?
Spring 是一个框架,是一个半成品的软件。有 20 个模块组成。它是一个容器管理对象,
对象之间的依赖关系。
(1) 轻量
Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核心功能的所需
的 jar 总共在 3M 左右。
Spring 框架运行占用的资源少,运行效率高。不依赖其他 jar
(2) 针对接口编程,解耦合
Spring 提供了 Ioc 控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的
对象创建方式,现在由容器完成。对象之间的依赖解耦合。
(3) AOP 编程的支持
通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现
的功能可以通过 AOP 轻松应付
在 Spring 中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活地
进行事务的管理,提高开发效率和质量。
(4) 方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,相反 Spring 可以降低各种框架的使用难度,Spring
提供了对各种优秀框架(如 Struts,Hibernate、MyBatis)等的直接支持。简化框架的使用。
(5) 非侵入式
所谓非侵入式是指,Spring 框架的 API 不会在业务逻辑上出现,由于业务逻辑中没有Spring 的 API,所以业务逻辑可以从 Spring 框架快速的移植到其他框架,即与环境无关。
(6) 容器
Spring 作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。可以通
过配置文件,来定义对象,以及设置与其他对象的依赖关系。

1.2 Spring 框架是什么(掌握)
Spring精讲课程
Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,它是为了解决企业应用开发的复杂性而创建的。Spring 的核心是控制反转(IoC)和面向切面编程(AOP)。简单来说,Spring 是一个分层的 Java SE/EE 轻量级开源框架 。
Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。就是让对象和对象(模块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在 Spring 中说明对象(模块)的关系。
Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度。IoC 使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成“织入”。

1.3 Spring 体系结构(了解)
Spring精讲课程Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、Web、面向切面编程(AOP, Aspects)、应用服务器设备管理(Instrumentation)、消息发送(Messaging)、核心容器(Core Container)和测试(Test)。
1.5 Spring4 框架解压目录及 Jar 包说明(了解)
Spring精讲课程Spring精讲课程

第2章 IoC 控制反转
控制反转(IoC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的装配和管理。
IoC 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式是依赖注入。应用广泛。
依赖:classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完成功能,即 classA对 classB 有依赖。
Ioc 的实现:
1> 依赖查找:DL ( Dependency Lookup ), 容器提供回调接口和上下文环境给组件。
2>依赖注入:DI (Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。
依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持 POJO 之间依赖关系的管理。
依赖注入是目前最优秀的解耦方式。依赖注入让 Spring 的 Bean 之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。
2.1 Spring 的第一个程序(掌握)
在普通三层架构的基础上,将程序修改为 Spring 框架程序
举例:01-primay
2.1.1 导入 Jar 包
首先,导入 Spring 程序开发的四个基本 jar 包。
Spring精讲课程日志:http://commons.apache.org/proper/commons-logging/download_logging.cgi
Spring精讲课程其次,导入日志相关的 Jar 包。commons.logging.jar 该文件只是日志记录的实现规范,并没有具体的实现(相当于日志操作的接口定义)。
这里日志的实现使用 log4j,故还需要 log4j.jar。
最后,导入 JUnit 测试 Jar 包 junit-4.9.jar。
Spring 基本编程,共需 7 个 Jar 包即可。
Spring精讲课程 定义接口与实体类
Spring精讲课程Spring精讲课程2.1.3 创建 Spring 配置文件
Spring 配置文件的文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。文件约束在%SPRING_HOME%\docs\spring-framework-reference\html\xsd-configuration.html 文件中。
Spring精讲课程Spring精讲课程注意,Spring 配置文件中使用的约束文件为 xsd 文件。若 Eclipse 中没有自动提示功能,则需要将约束要查找的域名地址指向本地的 xsd 文件。相应的 xsd 文件在 Spring 框架解压目录下的 schema 目录的相应子目录中。
约束文件:xsd(xml schema definition) xml 文档结构定义。
作用:验证 xml 文档的逻辑结构是否正确。
1.定义一个 xml 文档中都有什么元素
2.定义一个 xml 文档中都有什么属性
3.定义一个 xml 文档中元素可以有哪些子元素,以及元素的顺序。
4.定义一个 xml 文档中元素和属性的数据类型。
这里需要的是 spring-beans.xsd 约束文件,故需要在 beans 子目录中查找相应版本的约束文件。
Spring精讲课程Spring精讲课程:用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。
2.1.4 配置不能联网,本机的约束文件
先拷贝约束文件的 url 地址, 然后点击 Eclipse 的 windows 菜单下面的 Perferences
Spring精讲课程2.1.5 定义测试类
Spring精讲课程2.1.6 容器接口和实现类
(1) ApplicationContext 接口(容器)
ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现类有两个。通过 Ctrl +T 查看:
Spring精讲课程A、配置文件在类路径下
若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现类进行加载。

Spring精讲课程B、 配置文件在本地目录中
若 Spring 配置文件存放在本地磁盘目录中,则使用 FileSystemXmlApplicationContext 实现类进行加载。
Spring精讲课程C、 配置文件在项目根路径下
若 Spring 配置文件存放在项目的根路径下,同样使用 FileSystemXmlApplicationContext实现类进行加载。
下面是存放在项目根路径下的情况,该配置文件与 src 目录同级,而非在 src 中。
Spring精讲课程D、ApplicationContext 容器中对象的装配时机
ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。Spring精讲课程
2.2 Bean 的装配
举例:beanAssemble 项目
Bean 的装配,即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配。
2.2.1 默认装配方式(掌握)
代码通过 getBean()方式从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参构造器,创建空值的实例对象。
Spring精讲课程Spring精讲课程2.2.2 容器中 Bean 的作用域(掌握)
当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。
(1)singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
(2)prototype:原型模式。即每次使用 getBean 方法获取的同一个的实例都是一个新的实例。
(3)request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
(4)session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
注意:
(1)对于 scope 的值 request、session 只有在 Web 应用中使用 Spring 时,该作用域才有效。
(2)对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
(3)对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。
举例:
Spring精讲课程2.2.3 定制 Bean 的生命始末(掌握)
可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。
举例:
首先,这些方法需要在 Bean 类中事先定义好:是方法名随意的 public void 方法。
Spring精讲课程其次,在配置文件的标签中增加如下属性:
init-method:指定初始化方法的方法名
destroy-method:指定销毁方法的方法名
Spring精讲课程注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
(1)Bean 为 singleton,即单例
(2)要确保容器关闭。接口 ApplicationContext 没有 close()方法,但其实现类有。所以,可以将 ApplicationContext 强转为其实现类对象,或直接创建的就是实现类对象。

Spring精讲课程2.3 基于 XML 的 DI
举例:项目 di-xml
2.3.1 注入分类
bean 实例在调用无参构造器创建了空值对象后,就要对 bean 对象的属性进行初始化。
初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类:设值注入、构造注入。
(1) 设值注入(掌握)
设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用
Spring精讲课程Spring精讲课程Spring精讲课程对于其它 Bean 对象的引用,除了标签的 ref 属性外,还可以使用标签。
(2) 构造注入(理解)
构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。
举例:标签中用于指定参数的属性有:
1> name:指定参数名称。
2>index:指明该参数对应着构造器的第几个参数,从 0 开始。不过,该属性不要也行,
但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数
顺序一致。

Spring精讲课程
2.3.2 具有集合性质的属性注入(掌握)
/**MyCollections **/
package com.bernode.ba04;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class MyCollections {

private String [] mystr;
private Set<String> myset;
private List<Student> mylist;
private Map<String,Integer> mymap;
// Properties也是key-value的结构, key-value都是String类型。
private Properties myprop;

//复杂的集合类型
private List<Map<String,String>> mylistmap;

public void setMylistmap(List<Map<String, String>> mylistmap) {
	this.mylistmap = mylistmap;
}
public void setMystr(String[] mystr) {
	this.mystr = mystr;
}
public void setMyset(Set<String> myset) {
	this.myset = myset;
}
public void setMylist(List<Student> mylist) {
	this.mylist = mylist;
}
public void setMymap(Map<String, Integer> mymap) {
	this.mymap = mymap;
}
public void setMyprop(Properties myprop) {
	this.myprop = myprop;
}
@Override
public String toString() {
	return "MyCollections [mylistmap=" + mylistmap + "]";
}

}

/MyTest**/

package com. de.ba04;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class MyTest {
/**
*/
@Test
public void test01(){
String configLocation=“com/bjpowernode/ba04/applicationContext.xml”; //类路径的根目录
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);

	MyCollections coll = (MyCollections) ctx.getBean("myCollections");
	System.out.println("coll:"+coll);
}

}

/***applicationContext.xml/

<?xml version="1.0" encoding="UTF-8"?>

 <!--  给具有集性质的属性赋值 
                什么类型的属性,就用什么类型的子标签, 
                集合中是简单类型就用value, 是对象类型就用ref
 -->
 <bean id="myCollections" class="com.bjpowernode.ba04.MyCollections">
    <!-- Array<String> -->
 	<property name="mystr">
 		<array>
 			<value>大兴区</value>
 			<value>朝阳区</value>
 		</array>
 	</property>
 	
 	<!-- Set<String> -->
 	<property name="myset">
 		<set>
 			<value>北京</value>
 			<value>上海</value>
 			<value>杭州</value>
 		</set>
 	</property>
 	
 	<!-- List<Student> -->
 	<property name="mylist">
 		<list>
 			<ref bean="myStudent"/>
 			<ref bean="myStudent1"/>
 			<ref bean="myStudent2"/>
 		</list>
 	</property>
 	
 	<!-- Map<String,Integer> -->
 	<property name="mymap">
 		<map>
 			<entry key="weight" value="80" /> <!-- key-value -->
 			<entry key="height" value="180" />
 		</map>
 	</property>
 	
 	<!-- Properties -->
 	<property name="myprop">
 		<props>
 			<prop key="tel">010-14678979</prop> <!-- key-value -->
 			<prop key="phone">1234578978</prop>
 		</props>
 	</property>
 	
 	<!-- List<Map<String,String>> -->
 	<property name="mylistmap">
 		<list>
 			<map> <!-- 0 -->
 				<entry key="weight" value="80kg" />
 				<entry key="height" value="180cm" />
 			</map>
 			
 			<map> <!-- 1 -->
 				<entry key="tel" value="1534879" />
 				<entry key="phone" value="1649879" />
 			</map>
 		</list>
 	
 	</property>
 </bean>

/********************************************************/
2.3.3 对于引用类型属性的自动注入
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签
设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属
性)。根据自动注入判断标准的不同,可以分为两种:
byName:根据名称自动注入
byType:根据类型自动注入
(1) byName 方式自动注入(理解)
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
举例:
Spring精讲课程(2) byType 方式自动注入(理解)
使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
举例:
Spring精讲课程Spring精讲课程2.3.4 为应用指定多个 Spring 配置文件(掌握)
在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring 配置文件分解成多个配置文件。
(1) 平等关系的配置文件(掌握)
将配置文件分解为地位平等的多个配置文件,并将所有配置文件的路径定义为一个String 数组,将其作为容器初始化参数出现。其将与可变参的容器构造器匹配。
Spring精讲课程各配置文件间为并列关系,不分主次。
举例:
Spring精讲课程(2) 包含关系的配置文件(掌握)
各配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。
举例:
Spring精讲课程也可使用通配符*。但,此时要求父配置文件名不能满足所能匹配的格式,否则将出现循环递归包含。就本例而言,父配置文件不能匹配 spring-.xml 的格式,即不能起名为spring-total.xml。
Spring精讲课程2.4 基于注解的 DI
举例:di-annotation 项目
对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变,完成以下三个步骤。
(1)导入 AOP 的 Jar 包。因为注解的后台实现用到了 AOP 编程。
Spring精讲课程
Spring精讲课程(3)需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
Spring精讲课程3-1)使用多个 context:component-scan 指定不同的包路径
Spring精讲课程3-2)指定 base-package 的值使用分隔符
分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格。
逗号分隔:
Spring精讲课程3-3)base-package 是指定到父包名
base-package 的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。
Spring精讲课程
Spring精讲课程2.4.1 定义 Bean 的注解@Component(掌握)
需要在类上使用注解@Component,该注解的 value 属性用于指定该 bean 的 id 值。
举例:di01
Spring精讲课程另外,Spring 还提供了 3 个功能基本和@Component 等效的注解:
1> @Repository 用于对 DAO 实现类进行注解
2> @Service 用于对 Service 实现类进行注解
3> @Controller 用于对 Controller 实现类进行注解
之所以创建这三个功能与@Component 等效的注解,是为了以后对其进行功能上的扩展。
@Component 不指定 value 属性,bean 的 id 是类名的首字母小写。
Spring精讲课程
2.4.2 简单类型属性注入@Value(掌握)
需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
举例:Spring精讲课程2.4.3 byType 自动注入@Autowired(掌握)
需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
举例:
Spring精讲课程2.4.4 byName 自动注入@Autowired 与@Qualifier(掌握)
需要在引用属性上联合使用注解@Autowired 与@Qualifier。@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。同样类中无需 setter,也可加到 setter 上。
举例:Spring精讲课程
@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运
行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。
Spring精讲课程

2.4.5 JDK 注解@Resource 自动注入 (掌握)
Spring提供了对 jdk中@Resource注解的支持。@Resource 注解既可以按名称匹配Bean,也可以按类型匹配 Bean。默认是按名称注入。使用该注解,要求 JDK 必须是 6 及以上版本。
@Resource 可在属性上,也可在 set 方法上。
(1) byType 注入引用类型属性
@Resource 注解若不带任何参数,采用默认按名称的方式注入,按名称不能注入 bean,则会按照类型进行 Bean 的匹配注入。
举例:
Spring精讲课程(2) byName 注入引用类型属性
@Resource 注解指定其 name 属性,则 name 的值即为按照名称进行匹配的 Bean 的 id。
Spring精讲课程2.4.6 Bean 的生命始末@PostConstruct 与@PreDestroy(掌握)
在方法上使用@PostConstruct 与原来的 init-method 等效。在方法上使用@PreDestroy,与 destroy-method 等效。
举例:
Spring精讲课程2.4.7 注解与 XML 的对比
注解的好处是,配置方便,直观。但其弊端也显而易见:以硬编码的方式写入到了 Java
代码中,其修改是需要重新编译代码的。
XML 配置方式的最大好处是,对其所做修改,无需编译代码,只需重启服务器即可将新
的配置加载。
注解的特点是高效(代码少,没有配置文件的书写那么复杂),XML 配置方式的特点是
灵活(无需修改源代码),
再有如果要使用的类不是自己编写的,没有源代码。那也使用不了@Compoent 等注解,
此时使用 XML 进行配置 bean.