spring介绍
spring是分层的Java SE/EE应用的full-stack轻量级开源框架。它是以IOC(Inversion Of Control)控制反转和AOP(Aspect Oriented Programming)面向切面编程为核心,提供了表现层springmvc和持久层spring JDBC以及业务层的事务管理等企业级应用解决方案。还能实现将开源世界中众多优秀的第三方框架和类库整合,成为越来越受欢迎的JavaEE企业级应用框架。
spring发展历程
-
1997年IBM提出了EJB的思想
-
1998年,SUN制定开发标准规范EJB1.0
-
1999年,EJB1.1发布
-
2001年,EJB2.0发布
-
2003年,EJB2.1发布
-
2006年,EJB3.0发布
-
Rod Johnson(spring之父)
Expert One-to-One J2EE Design and Development(2002) 阐述了J2EE 使用EJB 开发设计的优点及解决方案 Expert One-to-One J2EE Development without EJB(2004) 阐述了J2EE 开发不使用EJB 的解决方式(Spring 雏形)
-
2017 年9 月份发布了spring 的最新版本spring 5.0 通用版(GA)
spring优点
- IOC解耦,简化开发
通过spring提供的IOC容器,可以将对象间的依赖关系交由spring管理,避免硬编码造成的程序间过渡耦合。用户也不必再为了编写工厂类,属性文件解析等底层实现编写代码,可以更加专注于业务系统需求的实现。
- AOP面向切面编程支持
通过spring的AOP功能,方便实现面向切面编程,很多使用传统OOP编程不容易实现的业务功能,可以通过AOP轻松实现。比如事务管理,日志功能。
- 声明式事务支持
通过声明式方式灵活实现事务管理,提高开发效率和质量,将我们(程序员)从单调烦闷的事务管理代码中解脱出来。
- 方便程序测试
可以使用非容器依赖的方式进行程序测试工作,让测试工作更加轻松,更加方便。
- 集成第三方优秀框架
spring框架降低了第三方框架的集成使用难度,提供了对各种框架(hibernate、struts2、quartz、mybatis、springmvc等)的直接支持。
- 学习java源码的经典案例
spring的源码设计精妙、结构清晰、匠心独具,处处体现了大师对java设计模式的灵活应用以及java技术的高深造诣。它的源代码无疑是java技术的最佳实践案例。
spring体系结构
spring的IOC
说明:基于xml的IOC配置。
IOC介绍
IOC(Inversion Of Control)控制反转。是面向对象编程的一个重要法则,用于削减计算机程序间的耦合问题。控制反转中分为两种类型,一种是DI(Dependency Injection)依赖注入;另外一种是DL(Dependency Lookup)依赖查找。实际应用中依赖注入使用更多。
IOC入门案例
准备spring环境
官网地址
https://spring.io/
下载地址
http://repo.springsource.org/libs-release-local/org/springframework/spring/
本地下载好的文件
解压目录结构
-
doc:API文档
-
libs:jar包和源码包
-
schema:约束文件
创建项目
模拟项目中的三层对象
编写持久层对象
- 编写客户dao接口
package cn.itheima.dao;
/**
* 客户dao接口
*/
public interface CustomerDao {
/**
* 保存客户
*/
void saveCustomer();
}
- 编写客户dao实现类
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
/**
* 客户dao实现类
*/
public class CustomerDaoImpl implements CustomerDao {
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println("保存客户。");
}
}
编写业务层对象
- 编写客户service接口
package cn.itheima.service;
/**
* 客户service接口
*/
public interface CustomerService {
/**
* 保存客户
*/
void saveCustomer();
}
- 编写客户service实现类
package cn.itheima.service.impl;
import cn.itheima.dao.CustomerDao;
import cn.itheima.dao.impl.CustomerDaoImpl;
import cn.itheima.service.CustomerService;
/**
* 客户service实现类
*/
public class CustomerServiceImpl implements CustomerService {
// 在业务层中,调用持久层dao对象
private CustomerDao customerDao = new CustomerDaoImpl();
/**
* 保存客户
*/
public void saveCustomer() {
customerDao.saveCustomer();
}
}
编写表现层对象
package cn.itheima.controller;
import cn.itheima.service.CustomerService;
import cn.itheima.service.impl.CustomerServiceImpl;
/**
* 客户表现层对象
*/
public class CustomerController {
public static void main(String[] args) {
// 表现层中,调用业务层对象
CustomerService customerService = new CustomerServiceImpl();
customerService.saveCustomer();
}
}
搭建spring入门开发环境
配置pom.xml文件,加入spring基础开发依赖包
pom文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itheima</groupId>
<artifactId>spring-day01-03helloworld</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-day01-03helloworld</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- spring版本号 -->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
创建bean.xml文件
说明:该配置文件是spring框架的主配置文件,文件位置为类的根路径下,文件名称可以修改。
导入约束:
配置bean.xml文件,让spring框架管理service和dao资源
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置客户service,说明:
bean标签:配置javaBean对象
属性:
id:给bean对象取一个唯一标识名称
class:指定创建对象的类名称(指定全限定名称)
细节:默认使用无参数构造方法创建对象。如果此时没有无参构造方法,创建对象会失败
-->
<bean id="customerService" class="cn.itheima.service.impl.CustomerServiceImpl"></bean>
<!--配置客户dao-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"></bean>
</beans>
修改表现层对象,进行测试
/**
* 从spring框架的IOC容器中,获取客户service对象
* 说明:
* 1.spring框架提供了一个大工厂:ApplicationContext,它提供了根据bean的名称
* 获取bean的方法,它是一个接口。
* 2.它有两个常用的实现类:
* ClassPathXmlApplicationContext:从类的根路径下加载spring配置文件(实际项目中使用较多,掌握)
* FileSystemXmlApplicationContext:从文件路径下加载spring配置文件(一般不用,了解即可)
*/
// 1.加载spring配置文件,创建spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 2.从容器中获取客户service对象
CustomerService customerService = (CustomerService) context.getBean("customerService");
// 3.保存客户
customerService.saveCustomer();
基于xml配置的IOC细节
spring中工厂类结构
图一:
图二:
ApplicationContext接口常用实现类
- ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件,使用较多。【掌握】
- FileSystemXmlApplicationContext
它是从文件系统路径下加载配置文件,一般不使用。【了解】
- AnnotationConfigApplicationContext
当使用注解配置开发时候,需要使用它来创建spring容器。【掌握】
工厂接口BeanFactory与ApplicationContext区别
-
BeanFactory是spring容器的顶层接口
-
ApplicationContext是它的子接口
-
它们创建对象的时间点不一样
ApplicationContext:只要一加载配置文件,立即就创建配置文件中的对象。采用立即创建的思想
BeanFactory:什么时候使用对象,什么时候创建配置文件中的对象。采用延迟创建的思想。
案例演示
创建项目
改造客户dao对象,增加无参构造方法
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
/**
* 客户dao实现类
*/
public class CustomerDaoImpl implements CustomerDao {
/**
* 无参数构造方法
*/
public CustomerDaoImpl(){
System.out.println("正在创建客户dao对象。");
}
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println("保存客户。");
}
}
改造客户controller对象,演示ApplicationContext接口
public static void main(String[] args) {
/**
* 讲解ApplicationContext与BeanFactory区别
* 说明:
* 1.ApplicationContext:只要一加载配置文件,就立即创建配置文件中的对象。立即加载。
* */
// 1.加载spring配置文件,创建spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("加载bean.xml文件完毕,创建好spring容器。");
// 2.从容器中获取客户dao对象
CustomerDao customerDao= (CustomerDao) context.getBean("customerDao");
// 3.保存客户
customerDao.saveCustomer();
}
改造客户controller对象,演示BeanFactory接口
public static void main(String[] args) {
/**
* 讲解ApplicationContext与BeanFactory区别
* 说明:
* 1.ApplicationContext:只要一加载配置文件,就立即创建配置文件中的对象。立即加载。
* 2.BeanFactory:什么时候使用对象,什么时候创建。延迟加载【了解】
* */
// 1.加载spring配置文件,创建spring容器
/* ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("加载bean.xml文件完毕,创建好spring容器。");*/
// 使用BeanFactory接口,加载spring配置文件,创建spring容器
Resource resource = new ClassPathResource("bean.xml");
BeanFactory context = new XmlBeanFactory(resource);
System.out.println("加载bean.xml文件完毕,创建好spring容器。");
// 2.从容器中获取客户dao对象
CustomerDao customerDao= (CustomerDao) context.getBean("customerDao");
// 3.保存客户
customerDao.saveCustomer();
}
bean标签细节
bean标签作用
配置javaBean对象,让spring容器创建管理。默认调用类中无参数的构造方法创建对象。
bean标签属性
属性 | 说明 |
---|---|
id | bean的唯一标识名称 |
class | 类的全限定名称 |
scope | 设置bean的作用范围。 取值: singleton:单例。默认值 prototype:多例 request:web项目中,将对象存入request域中【了解】 session:web项目中,将对象存入session域中【了解】 globalsession:web项目中,应用在集群环境,如果没有集群环境,相当于session【了解】 |
init-method | 指定类中初始化方法的名称,在构造方法执行完毕后立即执行【了解】 |
destroy-method | 指定类中销毁方法名称,在销毁spring容器前执行【了解】 |
bean的作用范围和生命周期
作用范围 | 生命周期 | |
---|---|---|
单例对象:scope=”singleton” | 一个应用中只有一个对象实例 | 出生:加载配置文件,容器创建,对象出生 活着:只要容器存在,对象就一直活着 死亡:容器销毁,对象死亡 |
多例对象:scope=”prototype” | 在一次使用过程中 | 出生:第一次获取对象,对象出生 活着:在一次使用过程中,对象活着 死亡:当对象不再使用,也没有被其它对象引用,交由垃圾回收器回收 |
案例演示
创建项目
scope属性【掌握】
- 默认情况:单例
<!--配置客户dao,说明:
scope属性:
1.默认情况,是单例,相当于singleton
-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"></bean>
- scope取值singleton
<!--配置客户dao,说明:
scope属性:
1.默认情况,是单例,相当于singleton
2.取值singleton
-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"
scope="singleton"></bean>
- scope取值prototype
<!--配置客户dao,说明:
scope属性:
1.默认情况,是单例,相当于singleton
2.取值singleton
3.取值prototype
-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"
scope="prototype"></bean>
init-method和destroy-method属性【了解】
- 改造客户dao实现类,增加初始化和销毁方法
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
/**
* 客户dao实现类
*/
public class CustomerDaoImpl implements CustomerDao {
/**
* 无参数构造方法
*/
public CustomerDaoImpl(){
System.out.println("正在创建客户dao对象。");
}
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println("保存客户。");
}
/**
* 初始化方法:init-method
*/
public void init(){
System.out.println("正在执行初始化操作。");
}
/**
* 销毁方法:destroy-method
*/
public void destroy(){
System.out.println("正在执行销毁操作。");
}
}
- 配置bean.xml文件,增加init-method和destroy-method属性
<!--配置客户dao,说明:
scope属性:
1.默认情况,是单例,相当于singleton
2.取值singleton
3.取值prototype
init-method属性:执行初始化资源操作,在构造方法执行后立即执行
destroy-method属性:执行销毁资源操作,在销毁spring容器前执行
-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"
scope="singleton" init-method="init" destroy-method="destroy"></bean>
- 改造客户controller对象,测试
实例化bean的三种方式
第一种方式:使用无参构造方法【掌握】
<!--配置客户dao,说明:
1.讲解使用无参数构造方法实例化bean对象
-->
<bean id="customerDao" class="cn.itheima.dao.impl.CustomerDaoImpl"></bean>
第二种方式:使用静态工厂方法【了解】
package cn.itheima.factory;
import cn.itheima.dao.CustomerDao;
import cn.itheima.dao.impl.CustomerDaoImpl;
/**
* 讲解使用静态工厂方法实例化bean
*/
public class StaticFactory {
/**
* 静态方法,创建客户dao对象
*/
public static CustomerDao createCustomerDao(){
System.out.println("静态工厂方法准备创建对象。");
return new CustomerDaoImpl();
}
}
<!--静态工厂方法实例化bean,说明:
1.factory-method属性:配置创建对象的静态工厂方法
-->
<bean id="staticDao" class="cn.itheima.factory.StaticFactory"
factory-method="createCustomerDao">
</bean>
第三种方式:使用实例工厂方法【了解】
package cn.itheima.factory;
import cn.itheima.dao.CustomerDao;
import cn.itheima.dao.impl.CustomerDaoImpl;
/**
* 讲解实例工厂方法实例化bean
*/
public class InstanceFactory {
/**
* 普通方法,创建客户dao对象
*/
public CustomerDao createCustomerDao(){
System.out.println("----------------华丽丽分割线--------------");
System.out.println("实例工厂方法准备创建对象。");
return new CustomerDaoImpl();
}
}
<!--实例工厂方法实例化bean,说明:
第一步:配置实例工厂对象
第二步:通过factory-bean指定实例工厂对象,通过factory-method指定实例工厂方法。创建目标对象
-->
<bean id="instanceFactory" class="cn.itheima.factory.InstanceFactory"></bean>
<bean id="instanceDao" factory-bean="instanceFactory" factory-method="createCustomerDao"></bean>
依赖注入
依赖注入介绍
在我们刚才完成的spring的IOC案例中,已经让spring框架为我们创建了客户业务层、客户持久层对象。但是层与层之间的关系没有维护起来。接下来我们来看spring框架的依赖注入。
首先给依赖注入下一个定义:依赖注入(Dependency Injection),它是spring框架核心IOC的具体实现。我们在编写程序代码时,通过控制反转,把对象交给spring管理。但是代码中必然会存在一定的依赖关系。比如在业务层(service)中,需要引用持久层(dao)对象。那么这种层与层之间的关系,我们也交给spring来维护。
简单理解:依赖注入就是给成员变量赋值。
依赖注入类型
构造方法注入【掌握】
构造方法注入。顾名思义,就是通过类中的构造方法,给成员变量赋值。
创建项目
编写构造方法注入类
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
import java.util.Date;
/**
* 讲解构造方法注入
*/
public class ConstructorDaoImpl implements CustomerDao {
private int id;
private String name;
private Integer age;
private Date birthday;
/**
* 构造方法
*/
public ConstructorDaoImpl(int id, String name, Integer age, Date birthday) {
this.id = id;
this.name = name;
this.age = age;
this.birthday = birthday;
}
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println("id:"+id+",name:"+name+",age:"+age+",birthday:"+birthday);
}
}
配置bean.xml
<!--讲解构造方法注入,说明:
constructor-arg:指定通过构造方法,给成员变量赋值
属性:
index:指定成员变量在构造方法参数列表中的索引
name:指定成员变量在构造方法参数列表中的名称(index和name二者使用一个即可)
type:指定成员变量的类型(一般不需要指定,默认即可)
value:给java简单类型成员变量赋值(八种基本类型+字符串)
ref:给其它bean类型成员变量赋值
-->
<bean id="constructorDao" class="cn.itheima.dao.impl.ConstructorDaoImpl">
<constructor-arg index="0" name="id" type="int" value="1" ></constructor-arg>
<constructor-arg name="name" value="小明"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--配置日期类型bean对象-->
<bean id="now" class="java.util.Date"></bean>
测试
set方法注入【掌握】
set方法注入。顾名思义,就是通过类中的set方法,给成员变量赋值。
编写set方法注入类
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
import java.util.Date;
/**
* 讲解set方法注入
*/
public class SetDaoImpl implements CustomerDao {
private int id;
private String name;
private Integer age;
private Date birthday;
/**
* ============================setter方法=========================
*/
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
/**
* ============================setter方法=========================
*/
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println("id:"+id+",name:"+name+",age:"+age+",birthday:"+birthday);
}
}
配置bean.xml
<!--讲解set方法注入,说明:
property:指定通过set方法,给成员变量赋值
属性:
name:指定成员变量的set方法名字去掉set后,首字母转小写的名称
value:给java简单类型(八种基本类型+字符串String)成员变量赋值
ref:给其它bean类型成员变量赋值
-->
<bean id="setDao" class="cn.itheima.dao.impl.SetDaoImpl">
<property name="id" value="1"></property>
<property name="name" value="小花"></property>
<property name="age" value="18"></property>
<property name="birthday" ref="now"></property>
</bean>
<!--配置日期类型bean对象-->
<bean id="now" class="java.util.Date"></bean>
测试
p名称空间注入【了解】
此种方式是通过在xml中导入p名称空间,使用p:property或者p:property-ref来注入数据,它的本质仍然是调用类中的set方法实现注入功能。
配置bean.xml
<!--讲解p名称空间注入,说明:
第一步:导入p名称空间(xmlns:p="http://www.springframework.org/schema/p")
第二步:通过p:property或者p:property-ref进行配置
p:property:给java简单类型成员变量赋值
p:property-ref:给其它bean类型成员变量赋值
-->
<bean id="pDao" class="cn.itheima.dao.impl.SetDaoImpl"
p:id="2" p:name="小黄" p:age="18" p:birthday-ref="now">
</bean>
<!--配置日期类型bean对象-->
<bean id="now" class="java.util.Date"></bean>
测试
c名称空间注入【了解】
此种方式是通过在xml中导入c名称空间,使用c:property或者c:property-ref来注入数据,它的本质仍然是调用类中的构造方法实现注入功能。
配置bean.xml
<!--讲解c名称空间注入,说明:
第一步:导入c名称空间(xmlns:c="http://www.springframework.org/schema/c")
第二步:通过c:property或者c:property-ref进行配置
c:property:给java简单类型成员变量赋值
c:property-ref:给其它bean类型成员变量赋值
-->
<bean id="cDao" class="cn.itheima.dao.impl.ConstructorDaoImpl"
c:id="3" c:name="小王" c:age="18" c:birthday-ref="now">
</bean>
</bean>
<!--配置日期类型bean对象-->
<bean id="now" class="java.util.Date"></bean>
测试
扩展:集合属性注入【了解】
顾名思义,就是给类中的集合成员成员变量赋值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。我们这里介绍注入数组,List,Set,Map,Properties。
编写集合属性注入类
package cn.itheima.dao.impl;
import cn.itheima.dao.CustomerDao;
import java.util.*;
/**
* 讲解集合属性注入
*/
public class CollectionDaoImpl implements CustomerDao {
private String[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties prop;
/**
* =========================setter方法=============================
*/
public void setArray(String[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setProp(Properties prop) {
this.prop = prop;
}
/**
* =========================setter方法=============================
*/
/**
* 保存客户
*/
public void saveCustomer() {
System.out.println(array !=null? Arrays.asList(array):"");
System.out.println(list);
System.out.println(set);
System.out.println(map);
System.out.println(prop);
}
}
配置bean.xml
<!--讲解集合属性注入,说明:
1.List结构:
array/list/set
2.Map结构:
map/prop
3.数据结构一致,标签可以互换
-->
<bean id="collectionDao" class="cn.itheima.dao.impl.CollectionDaoImpl">
<!--array-->
<property name="array">
<array>
<value>array1</value>
<value>array2</value>
</array>
</property>
<!--list-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<!--set-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<!--map-->
<property name="map">
<map>
<entry key="mapk1" value="mapv1"></entry>
<entry key="mapk2" value="mapv2"></entry>
</map>
</property>
<!--prop-->
<property name="prop">
<props>
<prop key="propk1">propv1</prop>
<prop key="propk2">propv2</prop>
</props>
</property>
</bean>