Spring框架-上篇

预备知识:Maven基础

Spring课程介绍

为什么学

  • 简化开发,降低企业级开发的复杂性
  • 框架整合,高效整合其他技术,提高企业级应用开发与运行效率

学什么

  • 简化开发

    • IoC
    • AOP
      • 事务处理
  • 框架整合

    • MyBatis
    • MyBatis-plus
    • Struts
    • Struts2
    • Hibernate

怎么学

  • 学习Spring框架设计思想
  • 学习基础操作,思考操作与思想间的联系
  • 学习案例,熟练应用操作的同时,体会思想

将学习的Spring技术

  • Spring Framework(Spring)
  • Spring Boot
  • Spring Cloud

Spring Framework系统架构

Spring Framework系统架构图

在这里插入图片描述

Data Access: 数据访问
Data Integration: 数据集成
Web: Web开发
AOP: 面向切面编程
Aspects: AOP思想实现
Core Container: 核心容器
Test: 单元测试与集成测试

Spring Framework学习线路

在这里插入图片描述


核心概念

  • 代码书写现状
    • 耦合度偏高
  • 解决方案
    • 使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
  • IoC(Inversion of Control)控制反转
    • 使用对象时,由主动new产生对象转换为由外部提供对象,对象的创建控制权由程序转移到外部,这种思想称为控制反转
  • Spring技术对IoC思想进行了实现
    • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的"外部"
    • Ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
      在这里插入图片描述在这里插入图片描述
  • DI(Dependency Injection)依赖注入
    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

在这里插入图片描述

  • 目标:充分解耦
    • 使用IoC容器管理bean(IoC)
    • 在IoC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终效果
    • 使用对象时不仅可以直接从Ioc容器中获取,并且获取到的bean已经绑定了所有的依赖关系

小结

  1. IoC/DI思想
IoC(Inversion of Control)控制反转
使用对像时,由主动new产生对象转换为由 外部提供对象,此过程中对象创建控制权由程序转移到 外部,此思想称为 控制反转
DI(Dependency Injection)依赖注入
在容器中 建立bean与bean之间的 依赖关系的整个过程,称为依赖注入
  1. IoC容器
    Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的"外部"
  2. Bean
    Ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

IoC案例

Io入门案例思路分析

1.管理什么?(Service与Dao)
2.如何将被管理的对象告知工oC容器?(配置)
3.被管理的对象交给IoC容器,如何获取到IoC容器?(接口)
4.IoC容器得到后,如何从容器中获取bean?(接口方法)
5.使用Spring导入哪些坐标?(pom.xml)

Ioc入门案例(XML版)

  1. 导入spring坐标
# pom.xml
<!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.10.RELEASE</versin>
</dependency>
  1. 定义Spring管理的类(接口)
public interface BookService{
	public void save();
}
public class BookServiceImpl implements BookService{
	private BookDao bookDao = new BookDaoImpl();
	public void save(){
		bookDao.save();
	}
}
  1. 创建Spring配置文件,配置对应类作为Spring管理的bean
    在这里插入图片描述
# 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
						https://www.springframework.org/schema/beans/spring-beans.xsd">
						
	<!--2.配置bean-->
	<!--bean标签标示配置bean
	id属性标示给bean起名字
	cLass属性表示给bean定义类型-->
	
	<bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/>
	<bean id="bookService"class="com.itheima.service.impl.BookServiceImpl"/>
</beans>
  1. 初始化Ioc容器(Spring核心容器/Spring容器),通过容器获取bean
public class App{
	public static void main(String[] args){
		//3.获取IoC容器
		//加载配置文件得到上下文对象,也就是容器对象
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//4.获取bean
		//获取资源
		//可以通过bean的id或name获取
		BookDao bookDao = (BookDao)ctx.getBean("bookDao");
		bookDao.save();
		BookService bookService = (BookService)ctx.getBean(s:"bookService");
		bookService.save();
	}
}

还是有new,未充分解耦

DI入门案例

DI入门案例思路分析

  1. 基于IoC管理bean
  2. Service中使用new形式创建的Dao对象是否保留?(否)
  3. Service中需要的Dao对象如何进入到Service中?(提供方法)
  4. Service与Dao间的关系如何描述?(配置)

DI入门案例(XML版)

①:删除使用new的形式创建对象的代码

public class BookServiceImpl implements BookService{
	private BookDao bookDao = new BookDaoImp1();
	public void save(){
		bookDao.save();
	}
}

②:提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService{
	private BookDao bookDao;
	public void save(){
		bookDao.save();
	}
	//这个set方法是容器在执行,往里边传对象
	public void setBookDao(BookDao bookDao){
		this.bookDao = bookDao;
	}
}

③:配置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
						https://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="bookService"class="com.itheima.di.service.impl.BookServiceImpl">
		<!--name是类BookServiceImpl类中的成员变量bookDao。ref可以是当前容器的bean的id或name-->
		<property name="bookDao"ref="bookDao"/>
	</bean>
	<bean id="bookDao"class="com.itheima.di.dao.impl.BookDaoImpl"/>
</beans>

bean

bean基础配置

类别描述
名称bean
类型标签
所属beans标签
功能定义Spring核心容器管理的对象
格式<beans>
      <bean/>
      <bean></bean>
</beans>
属性
列表
id:bean的id,使用容器可以通过id值获取对应的bean,在一个容器中id值唯一
class:bean的类型,即配置的bean的全路径类名
范例<bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService"class="com.itheima.service.impl.BookServiceImpl"></bean>

bean别名配置

类别描述
名称name
类型属性
所属bean标签
功能定义bean的别名,可定义多个,使用逗号(,)分号(;)空格(   )分隔
范例<bean id="bookDao" name="dao dao2 bookDaoImpl"class="com.itheima.dao.impl.BookDaoImpl"/>
<bean name="service,service2,bookServiceImpl"class="com.itheima.service.impl.BookServiceImpl"/>
  • 注意事项
    获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException NoSuchBeanDefinitionException:No bean named bookServiceImpl’available
    name和id的功能基本相同

bean作用范围配置

类别描述
名称scope
类型属性
所属bean标签
功能定义bean的作用范围,可选范围如下
●singleton:单例(默认)
●prototype:非单例
范例<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype" />
  • bean作用范围说明
    • 为什么bean默认为单例?
    • 适合交给容器进行管理的bean
      表现层对象
      业务层对象
      数据层对象
      工具对象
    • 不适合交给容器进行管理的bean
      封装实体的域对象(有状态,会记录成员变量的属性值)

bean

bean的实例化

bean的创建
  • bean本质上就是对象,创建bean使用构造方法完成
实例化bean的三种方式——构造方法(常用)
  • 提供可访问的构造方法
    • 这里的构造方法可以是私有的,因为调用内部用了反射
public class BookDaoImpl implements BookDao{
	/*public BookDaoImpl(){
		System.out.println("book constructor is running ...")
	}*/
	public void save(){
		System.out.println("book dao save ...")
	}
}
  • 配置
<!--方式一:构造方法实例化bean-->
<bean
	id="bookDao"
	class="com.itheima.dao.impl.BookDaoImpl"
	/>
public class AppForInstanceBook{
	public static void main(String[]args){
	//Spring也是用构造方法实例化bean
	ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	BookDao bookDao = (BookDao)ctx.getBean(s:"bookDao");
	
	bookDao.save();
}
  • 无参构造方法如果不存在,将抛出异常BeanCreationException
实例化bean的三种方式——静态工厂(了解)

使用工厂造对象:让工厂放回new的对象

  • 静态工厂
public class OrderDaoFactory{
	public static OrderDao getorderDao(){
		return new OrderDaoImpl();
	}
}

配置

<!--方式二:使用静态工厂实例化bean-->
<bean
	id="orderDao"
	factory-method="getorderDao"
	class="com.itheima.factory.OrderDaoFactory"
	/>
public class AppForInstanceOrder{
	public static void main(String[]args){
	//通过静态工厂创建对象
		OrderDao orderDao = OrderDaoFactory.getorderDao();
		orderDao.save();
	}
}
实例化bean的三种方式一实例工厂(了解)

实例工厂

public class UserDaoFactory{
	public /*static*/ UserDao getUserDao(){
		return new UserDaoImpl();
	}
}

配置

<bean id="userDaoFactory" class="com.itheima.factory.UserDaoFactory"/>
<!--配合userDao使用实际无意义-->
<bean
	id="userDao"
	factory-method="getUserDao" 	"方法名不固定每次需要配置"
	factory-bean="userDaoFactory"
	/>
实例化bean的第四种方式一FactoryBean(实用)
  • FactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao>{
	public UserDao getobject()throws Exception{
		return new UserDaoImpi();
	}
	public Class<?>getobjectType(){
		return UserDao.class;
	}
	//设置单、非单例
	/*public boolean issingleton(){
		return false;
	}*/
}

配置

<bean
	id="userDao"
	class="com.itheima.factory.UserDaoFactoryBean"
	/>
main{
	ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	UserDaouserDao (UserDao)ctx.getBean(s:"userDao");
	userDao.save();
}

bean的生命周期

生命周期:从创建到消亡的完整过程
bean生命周期:bean从创建到销毁的整体过程
bean生命周期控制:在bean创建后到销毁前做一些事情

bean生命周期控制一配置控制
  • 提供生命周期控制方法
public class BookDaoImpl implements BookDao{
	public void save(){
		System.out.println("book dao save ...")
	}
	public void init(){
		System.out.println("book init...");
	}
	public void destory(){
		System.out.println("book destory ...")
	}
}
  • 配置生命周期控制方法
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
bean生命周期控制一接口控制(了解)
  • 实现InitializingBean,DisposableBean接口
public class BookServiceImpl implements BookService InitializingBean,DisposableBean{
	public void save(){
		System.out.println("book service save ...")
	}
	public void afterPropertiesSet()throws Exception{
		System.out.println("afterPropertiesSet");
	}
	public void destroy()throws Exception{
		System.out.println("destroy");
	}
}
bean生命周期
初始化容器
1.创建对象(内存分配)】
2.执行构造方法
3.执行属性注入(set操作)
4.执行bean初始化方法
使用bean
1.执行业务操作
关闭/销毁容器
1.执行bean销毁方法
bean销毁时机
  • 容器关闭前会触发bean的销毁
    • 所以关闭容器就能销毁bean
  • 关闭容器方式:
    • 手工关闭容器
      ConfigurableApplicationContext接口close() 操作
    • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
      ConfigurableApplicationContext接口registerShutdownHook() 操作
public class AppForLifeCycle{
	public static void main(String[]args ){
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		ctx.registerShutdownHook();
		ctx.close();
	}
}

依赖注入(DI)

依赖注入方式

  • 思考:向一个类中传递数据的方式有几种?
    • 普通方法(set方法)
    • 构造方法
  • 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
    • 引用类型
    • 简单类型(基本数据类型与String)
  • 依赖注入方式
    • setter注入
      • 简单类型
      • 引用类型
    • 构造器注入
      • 简单类型
      • 引用类型
setter注入
  • setter注入——引用类型

    • 在bean中定义引用类型属性并提供可访问的set方法
    public class BookServiceImpl implements BookService{
    	private BookDaobookDao;
    	public void setBookDao(BookDaobookDao){
    		this.bookDaobookDao;
    	}
    }
    
    • 配置中使用propertyi标签ref属性注入引用类型对象
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
    	<!--name是类BookServiceImpl类中的成员变量bookDao。ref可以是当前容器的bean bookDao的id或name-->
    	<property name="bookDao" ref="bookDao"/>
    	<!--将bean bookDao依赖注入到私有属性bookDao-->
    </bean>
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    
  • setteri注入一简单类型

    • 在bean中定义引用类型属性并提供可访问的set方法
    public class BookDaoImpl implements BookDao{
    	private int connectionNumber;
    	public void setConnectionNumber(int connectionNumber){
    		this,connectionNumber connectionNumber;
    	}
    }
    
    • 配置中使用property标签value属性注入简单类型数据
    <bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl">
    	<!--将简单类型数据注入bookDao bean中的connectionNumber变量-->
    	<property name="connectionNumber"value="10"/>
    </bean>
    
构造器注入
  • 构造器注入一引用类型(了解)

    • 在bean中定义引用类型属性并提供可访问的构造方法
    public class BookServiceImpl implements BookService{
    	private BookDao bookDao;
    	public BookServiceImpl(BookDao bookDao){
    		this.bookDao = bookDao;
    	}
    }
    
    • 配置中使用constructor-arg标签ref属性注入引用类型对象
    <bean id="bookService"class="com.itheima.service.impl.BookServiceImpl">
    	<!--name是类BookServiceImpl类中构造方法的形参bookDao。ref可以是当前容器的bean bookDao的id或name-->
    	<constructor-arg name="bookDao"ref="bookDao"/>
    </bean>
    <bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/>
    
  • 构造器注入一简单类型(了解)

    • 在bean中定义引用类型属性并提供可访问的set方法
    public class BookDaoImpl implements BookDao
    	private int connectionNumber;
    	public void setConnectionNumber(int connectionNumber){
    		this.connectionNumber = connectionNumber;
    	}
    }
    
    • 配置中使用constructor-arg标签value属性注入简单类型数据
    <bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl">
    	<!--name是类中构造方法的形参connectionNumber。-->
    	<constructor-arg name="connectionNumber"value="10"/>
    </bean>
    
    • 因为依赖注入时name是类中构造方法的形参,耦合度很高,
    • 解决方案↓
  • 构造器注入—参数适配(了解)

    • 配置中使用constructor-arg标签type属性设置按形参类型注入
    <bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl">
    	<constructor-arg type="int" value="10"/>
    	<constructor-arg type="java.lang.String" value="mysql"/>
    </bean>
    
    • 配置中使用constructor-arg标签index属性设置按形参位置注入
    <bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl">
    	<constructor-arg index="0" value="10"/>
    	<constructor-arg index="1" value="mysql"/>
    </bean>
    
依赖注入方式选择
  1. 强制依赖使用构造器进行,使用setteri注入有概率不进行注入导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性强
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
  6. 自己开发的模块推荐使用setter注入
  • 总结
    建议使用setter注入:自己写就用setter
    第三方技术根据情况选择:用别人的类,别人提供构造器和setter就用setter,只有构造器用构造器

依赖自动装配

  • Ioc容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

  • 自动装配方式

    • 按类型(常用)
    • 按名称
    • 按构造方法
    • 不启用自动装配
  • 配置中使用bean标签autowire属性设置自动装配的类型

<bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService"class="com.itheima.service.impl.BookServiceImpl"autowire="byType/byName/bycontruct"/>
  • 依赖自动装配特征
    自动装配用于引用类型依赖注入,不能对简单类型进行操作
    使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
    使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
    自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

集合注入

  • 数组
    • 注入数组对象
<property name="array">
	<array>
		<value>100</value>
		<value>200</value>
		<value>300</value>
	</array>
</property>
  • List
    • 注入List对象(重点)
<property name="list">
	<list>
		<value>itcast</value>
		<value>itheima</value>
		<value>boxuegu</value>
	</list>
</property>
  • Set
    • 注入Set对象
<property name="set">
	<set>
		<value>itcast</value>
		<value>itheima</value>
		<value>boxuegu</value>
	</set>
</property>
  • Map
    • 注入Map对象(重点)
<property name="map">
	<map>
		<entry key="country"value="china"/>
		<entry key="province"value="henan"/>
		<entry key="city"value="kaifeng"/>
	</map>
</property>
  • Properties
    • 注入Propertiesi对象
<property name="properties">
	<props>
		<prop key="country">china</prop>
		<prop key="province">henan</prop>
		<prop key="city">kaifeng</prop>
	</props>
</property>

案例:数据源对象管理(第三方资源配置管理)

  • 导入druids坐标
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.16</version>
</dependency>
  • 配置数据源对象作为spring管理的bean
<bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource">
	<property name="driverclassName"value="com.mysql.jdbc.Driver"/>
	<property name="url"value="jdbc:mysq1://127.0.0.1:3306/spring_db"/>
	<property name="username"value="root"/>
	<property name="password"value="root"/>
</bean>

加载properties文件

  • 开启context命名空间
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">
</beans>	
  • 使用context命名空间,加载指定properties文件
<context:property-placeholder location="jdbc.properties"/>
  • 使用${)读取加载的属性值
<property name="username"value="${jdbc.username}"/>
加载properties配置文件的注意点
  • properties的变量可能会和系统环境变量冲突
  • 不加载系统属性
<context:property-placeholder location="jdbc.properties"system-properties-mode="NEVER"/>
  • 加载多个properties文件
<context:property-placeholder location="jdbc.properties,msg.properties"/>
  • 加载所有properties文件
<context:property-placeholder location="*.properties"/>
  • 加载properties.文件标准格式
<context:property-placeholder location="classpath:*.properties"/>
  • 从类路径或jar包中搜索并加载properties,文件
<context:property-placeholder location="classpath*:*properties"/>

容器(IOC)

创建容器

  • 方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  • 方式二:文件路径加载配置文件
ApplicationContext = ctx new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
  • 加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

获取bean

  • 方式一:使用bean名称获取
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
  • 方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
  • 方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);

容器类层次结构图

在这里插入图片描述

BeanFactory初始化

  • 类路径加载配置文件
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);

BookDao bookDao = bf.getBean("bookDao",BookDao.class);
bookDao.save();
  • BeanFactory创建完毕后,所有的bean均为延迟加载
    • 等同使用ClassPathXmlApplicationContext类+lazy-init
<bean id="bookDao"class="com.itheima.dao.impl.BookDaoImpl"lazy-init="true"/>

总结

容器相关

  • BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
  • ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
  • ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
  • ApplicationContext接口常用初始化类
    • ClassPathXmlApplicationContext
    • FileSystemXmlApplicationContext

bean相关

在这里插入图片描述

依赖注入相关

在这里插入图片描述

  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值