1.1 什么是Spring
spring是分层的java SE/EE应用full-stack(全栈)轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核。
提供了展现层SpringMVC和持久层Spring JDBCTemplate以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的java EE企业应用开源框架。
1.2 Spring的发展历程
1997年,IBM提出EJB的思想
1998年,SUN制定开发标准规范 EJB1.0
2001年,EJB2.0发布
2003年,EJB2.1发布
2006年,EJB3.0发布
Rod Johnson (Spring 之父)
2017年9月发布了Spring的最新版本Spring 5.0通用版 (GA)
1.3 Spring的优势
1)方便解耦,简化开发
通过Spring提供的IOC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度耦合。
2)AOP编程的支持
通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。
3)声明式事物的支持
只需要通过配置就可以完成对事物的管理,而无须手动编程。
4)方便程序的测试
Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
5)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持。
6)降低Jave EE API的使用难度。
Spring对Java EE开发中非常难用的一些API(如JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。
7)java源码是金典学习范例
Spring的源码设计巧妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。
1.4 Spring的体系结构
Spring框架至今已集成了20多个模块,这些模块分布在以下模块中:
-
核心容器(Core Container)
-
数据访问/集成(Data Access/Integration)层
-
Web层
-
AOP(Aspect Oriented Programming)模块
-
植入(Instrumentation)模块
-
消息传输(Messaging)
-
测试(Test)模块
Spring体系结构如下图:
2. Spring快速入门
2.1 Spring程序开发步骤
-
导入坐标
-
创建Bean
-
创建applicationContext.xml
-
在配置文件中进行配置Bean
-
创建ApplicationContext对象,通过getBean实例
2.2 导入Spring开发的基本包坐标
<properties>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<!-- 导入context坐标 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
2.3 编写UserDao接口和实现类
public interface UserDao { public void save(); }
public class UserDaoImpl implements UserDao{ @Override public void save() { System.out.println("save running......"); } }
2.4 创建Spring核心配置文件
在resources下创建applicationContext.xml配置文件
<?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">
</beans>
2.5 在配置文件中配置UserDaoImpl
<?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">
<bean id="userDao" class="com.ntect.dao.userDaoImpl"></bean>
</beans>
2.6 使用Spring的API获得Bean实例
package com.ntect.demo; import com.ntect.dao.userDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserDaoDemo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); userDao uDao =(userDao) ctx.getBean("userDao"); uDao.save(); } }
3. Spring配置文件
3.1 Bean标签基本配置
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
基本属性:
-
id: Bean实例在Spring容器中的唯一标识
-
class: Bean的全限定名称
3.2 Bean标签范围配置
scope指对象的作用范围 取值范围:
取值范围 | 说明 |
singleton |
默认的,单例范围 |
prototype |
多例的 |
request |
Web项目中,Spring创建一个Bean对象,将对象存到request域中 |
session |
Web项目中,Spring创建一个Bean对象,将对象存到session域中 |
global session |
Web项目中,应用在portlet环境,如果没有portlet环境,则global Session 相当于Session |
1)当scope属性取值为singleton时
Bean实例化个数:1个
Bean的实例化时机,当Spring核心配置文件被加载时,实例化配置的Bean实例(创建对象) Bean的生命周期
-
对象创建:当加载应用,创建容器时,对象就被创建了
-
对象运行:只要容器在,对象一直活着
-
对象销毁:当应用卸载,销毁容器时,对象被销毁
2)当scope属性取值为prototype时
Bean实例化个数:多个
Bean的实例化时机,当调用getBean()方法时,实例化Bean实例(创建对象) Bean的生命周期
-
对象创建:当使用对象时,创建新的对象实例
-
对象运行:只要容器在,对象一直活着
-
对象销毁:当对象长时间不用时,就被Java的垃圾回收器(GC)回收了
3.3 Bean生命周期配置
-
init-method:指定类中的初始化方法名称
-
destroy-method:指定类中销毁方法名称
3.4 Bean实例化三种方式
-
无参构造方法实例化
-
工厂静态方法实例化
-
工厂实例方法实例化
3.4.1 无参构造方法实例化
它会根据默认的无参构造方法来创建类对象,如果bean中没有默认的无参构造函数,将会创建失败。
<bean id="userDao" class="com.ntect.dao.userDaoImpl"></bean>
3.4.2工厂静态方法实例化
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实例类,而是静态工厂,Spring通过该属性知道由那个工厂来创建Bean实例。
package com.ntect.factory;
import com.ntect.dao.userDao;
import com.ntect.dao.userDaoImpl;
public class staticFactory {
public static userDao getUserDao() {
return new userDaoImpl();
}
}
<bean id="userDao" class="com.ntect.factory.staticFactory" factory-method="getUserDao"/>
3.4.3 工厂实例方法实例化
实例工厂方法与静态工厂方法只有一个不同:调用静态工厂方法只需要使用工厂类即可,而调用实例工厂方法则需要工厂实例。
package com.ntect.factory;
import com.ntect.dao.userDao;
import com.ntect.dao.userDaoImpl;
public class DynamicFactory {
public userDao getUserDao(){
return new userDaoImpl();
}
}
<bean id="factory" class="com.ntect.factory.DynamicFactory"/>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"/>
3.5 Bean的依赖注入分析
3.6 Bean的依赖注入概念
依赖注入(Dependency Injection):它是Spring框架核心IOC的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
3.7 Bean的依赖注入方式
-
构造方法
-
set方法
3.7.1 构造方法
创建有参构造
package com.ntect.service; import com.ntect.dao.userDao; public class UserServiceImpl implements userService{ private userDao userDao; public UserServiceImpl(userDao userDao){ this.userDao = userDao; } @Override public void save() { userDao.save(); } }
配置Spring容器调用有参构造方法进行注入
<bean id="userDao" class="com.ntect.dao.userDaoImpl"></bean>
<bean id="userService" class="com.ntect.service.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
</bean>
3.7.2 set方法
在UserServiceImpl中添加setUserDao方法
public interface userService {
public void save();
}
package com.ntect.service;
import com.ntect.dao.userDao;
public class UserServiceImpl implements userService{
private userDao userDao;
public void setUserDao(userDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
配置Spring容器调用set方法进行注入:
<bean id="userDao" class="com.ntect.dao.userDaoImpl"></bean>
<bean id="userService" class="com.ntect.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
P命名空间注入
P命名空间的本质也是set方法注入,但是比set方法方便,主要是在配置文件中。
首先需要引入P命名空间:
xmlns:p="http://www.springframework.org/schema/p"
然后需要修改注入方式:
<bean id="userDao" class="com.ntect.dao.userDaoImpl"/>
<bean id="userService" class="com.ntect.service.UserServiceImpl" p:userDao-ref = "userDao"></bean>
3.8 Bean的依赖注入的数据类型
注入数据的三种数据类型:
-
普通数据类型
-
引用数据类型
-
集合数据类型
3.8.1 普通数据类型注入
1 package com.ntect.dao; 2 3 public class userDaoImpl implements userDao{ 4 private String name; 5 private int age; 6 private String tel; 7 8 public String getName() { 9 return name; 10 } 11 12 public void setName(String name) { 13 this.name = name; 14 } 15 16 public int getAge() { 17 return age; 18 } 19 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public String getTel() { 25 return tel; 26 } 27 28 public void setTel(String tel) { 29 this.tel = tel; 30 } 31 32 @Override 33 public String toString() { 34 return "userDaoImpl{" + 35 "name='" + name + '\'' + 36 ", age=" + age + 37 ", tel='" + tel + '\'' + 38 '}'; 39 } 40 41 public void save() { 42 System.out.println("name:"+name+"--age:"+age+"--tel:"+tel); 43 System.out.println("userDao save running......"); 44 } 45 }
<bean id="userDao" class="com.ntect.dao.userDaoImpl">
<property name="name" value="麻子"/>
<property name="age" value="18"/>
<property name="tel" value="123456789120"/>
</bean>
3.8.2 集合数据类型注入
1 package com.ntect.dao;
2
3 import com.ntect.model.User;
4
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Properties;
8
9 public class userDaoImpl implements userDao{
10 private List<String> strList;
11 private Map<String, User> userMap;
12 private Properties properties;
13
14 public void setStrList(List<String> strList) {
15 this.strList = strList;
16 }
17
18 public void setUserMap(Map<String, User> userMap) {
19 this.userMap = userMap;
20 }
21
22 public void setProperties(Properties properties) {
23 this.properties = properties;
24 }
25
26 public void save() {
27 System.out.println("strLiist:"+strList);
28 System.out.println("userMap:"+userMap);
29 System.out.println("properties:"+properties);
30 System.out.println("userDao save running......");
31 }
32 }
1 <bean id="userDao" class="com.ntect.dao.userDaoImpl"> 2 <property name="strList"> 3 <list> 4 <value>1111</value> 5 <value>222</value> 6 <value>33</value> 7 </list> 8 </property> 9 <property name="userMap"> 10 <map> 11 <entry key="u1" value-ref="user1"/> 12 <entry key="u2" value-ref="user2"/> 13 </map> 14 </property> 15 <property name="properties"> 16 <props> 17 <prop key="p1">p21</prop> 18 <prop key="p2">p22</prop> 19 <prop key="p3">p23</prop> 20 </props> 21 </property> 22 </bean> 23 <bean id="user1" class="com.ntect.model.User"> 24 <property name="name" value="zhangsan"/> 25 <property name="address" value="chongqing"/> 26 </bean> 27 <bean id="user2" class="com.ntect.model.User"> 28 <property name="name" value="lisi"/> 29 <property name="address" value="tianjin"/> 30 </bean>
3.9 引入其他配置文件(可用于分模块化开发)
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载
<import resource="applicationContext-xxx.xml"/>
4. Spring相关API
4.1 ApplicationContext的继承体系
4.2 ApplicationContext的实现类
-
ClassPathXmlApplicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
这个实现类是从根路径下加载配置文件, 推荐使用这种, 也就是resources文件夹下
-
FileSystemXmlApplicationContext
ApplicationContext app = new FileSystemXmlApplicationContext("D:\\ideaWorkplace\\spring\\ntect_spring_ioc\\src\\main\\resource\\applicationContext.xml");
这个实现类是从磁盘路径上加载, 配置文件可以放在任意的位置
-
AnnotationConfigApplicationContext
当使用的是注解配置容器对象时, 才需要使用此类来创建spring容器
4.3 getBean()方法使用
1 public class UserDaoImpl implements UserDao {
2 List<User> userList;
3
4 public List<User> getUserList() {
5 return userList;
6 }
7
8 public void setUserList(List<User> userList) {
9 this.userList = userList;
10 }
11 }
1 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 2 userDao uDao =(userDao) ctx.getBean("userDao"); 3 userDao userDao = ctx.getBean(userDao.class);