目录
Spring介绍
为什么要学习Spring框架?
Spring技术是JavaEE开发的必备技能,企业开发技术选型命中率>=90%
废话不多说咱直接点进官网看看Spring | Home
上面 ↑ 这段话什么意思呢
Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的关注使其成为世界上最流行的Java框架。
世界上最流行的Java框架,太有必要学习一下了👀
专业角度:
- 简化开发, 降低企业级开发的复杂性
- 框架整合, 高校整合其他技术, 提高企业级应用开发与运行效率
学什么?
- 简化开发
- IOC (控制反转)
- AOP (面向切面编程)
- 框架整合
- MyBatis
- MyBatis-plus
怎么学
- 学习Spring框架设计思想
- 学习基础操作, 思考操作与思想间的联系
- 学习案例, 熟练应用操作的同时, 体会思想
Spring体系结构
Spring核心概念[重点]
IOC (控制反转)
- 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。通俗的讲就是“将new对象的权利交给Spring,我们从Spring中获取对象使用即可”, 大白话,咱不管创建, 咱直接拿来用.
- Spring技术对IOC思想进行了实现
- Spring提供了一个容器,称为IOC容器
DI (依赖注入)
- 在容器种建立 bean 与 bean 之间的依赖关系的过程,称为 依赖注入, 啥意思呢, 就是在一个Service的实现类中用到了Dao类中的方法,我们不用去new, Dao类的对象,直接调用方法即可
目标:
- 使用IOC容器管理Bean
- 在IOC容器中内将有依赖关系的bean进行关系绑定 (DI)
最终效果:
- 使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定好了所有的依赖关系
IOC入门案例[重点]
前边叭叭地说那么多,感觉听的也有点迷,咱呢,直接上波操作,不管是牛是马,拿出来遛一遛
案例的实现步骤
- 导入Spring坐标
- 定义Spring管理的类
- 创建Spring的配置文件, 配置对应类作为Spring管理的bean对象
- 初始化IOC容器(Spring核心容器/Spring容器), 通过容器获取bean对象
没创建项目怎么导入坐标,拿什么导入?
前创建个项目, 创建一个Maven项目
第一步, 导入Spring坐标
pom.xml导入Spring坐标
<dependencies>
<!-- Spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
</dependencies>
第二步, 定义Spring管理的类 (接口)
第三步, 创建Spring配置文件, 配置对应类作为Spring管理的bean对象
定义applicationContext.xml配置文件并配置UserServiceImpl
<?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标签:表示配置bean
id属性:表示给bean起名字
class属性:表示给bean定义类型
-->
<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl"/>
</beans>
注意事项 :
bean定义时,id属性在同一个上下文中(IOC容器中)不能重复.
第四步, 初始化IOC容器(Sprng核心容器/Spring容器), 通过容器获取Bean对象
再定义一个包名为test,用来测试
public class SpringTest {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) act.getBean("userService");
userService.add();
}
}
运行结果
DI入门案例[重点]
案例的实现步骤
- 删除使用new的形式创建对象的代码 , 也就是 UserServiceImpl 类中的UserDao 对象
- 提供依赖对象对应的 setter 方法
- 配置service与dao之间的关系
第一步,删除使用new的形式创建对象的代码
public class UserServiceImpl implements UserService {
// 1.删除使用new的形式创建对象的代码
private UserDao userDao;
public void add() {
System.out.println("UserServiceImpl");
userDao.save();
}
}
第二步,提供对应的setter方法
public class UserServiceImpl implements UserService {
// 1. 删除使用new的形式创建对象的代码
private UserDao userDao;
// 2. 提供对应的setter方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("UserServiceImpl");
userDao.save();
}
}
第三步,配置service与dao之间的关系
在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">
<bean id="userDao" class="priv.zlj.dao.impl.UserDaoImpl"/>
<!--
bean标签:表示配置bean
id属性:表示给bean起名字
class属性:表示给bean定义类型
-->
<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl">
<!--3. 配置server与dao的关系
property标签:表示配置当前bean的属性
name属性:表示配置哪一个具体的属性
ref属性:表示参照哪一个bean
-->
<property name="userDao" ref="userDao"/>
</bean>
</beans>
详细地说明一下这俩个案例地实现
不说大白话有点太官方了,听不懂,咱讲点对我来说能听懂的........
在IOC案例中,
首先呢, 创建一个maven项目, 为什么用Maven呢, nb...
我们第一步, 在pom.xml中导入了Spring的依赖, 为什么要导入?... 没有人家的依赖,玩什么IOC,DI....
第二步, 定义Spring要管理的类, 也就是 dao,service
第三步, 类定义好了, 我们要对其进行配置, 不配置拿什么对象?? 创建了一个配置文件applicationContext.xml 并且配置了 UserServiceImpl 的一个bean., 在这里呢用到了一个标签 也就是 <bean>标签<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl" />~ bean标签 : 表示配置bean
~ id属性 : 表示给bean 起个名字
~ class属性 : 表示给bean定义类型,也就是全类名,告诉人家,这个bean是哪来的注意事项, 在一个IOC容器中,bean的定义时,id属性不能重复
第四步, 初始化这个容器,也就是加载这个配置文件[applicationContext.xml),通过容器获取对象
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) act.getBean("userService"); userService.add();在DI 这个案例中
我们首先删除了在UserServiceImpl类中的UserDao的实例化操作,也就是new, 之前我们一直在说的我们不用自己去new, 交给外部(Spring)创建, 现在,没有实例化UserDao的对象,我们要是运行的话,肯定会看到一个空指针异常,没实例化就调用方法,肯定会Null....空指针异常所以我们第二步, 在UserServiceImpl类中提供对应的 setter 方法,为什么要提供setter方法呢,咱到后面在说, setter方法也有了, 这个时候就到 第三步了, 我们到applicationContext.xml文件中配置这俩的关系, 配UserServiceImpl和UserDao的关系, UserServiceImpl的bean我们有了, 还得创建个 UserDao的 bean吧, 不能说你没创建bean 我给你变出来一个吧,
<bean id="userDao" class="priv.zlj.dao.impl.UserDaoImpl"/> 这时候,就要配置关系了, 在UserServiceImpl类中有一个属性 UserDao, 唉~,还有对应的setter方法, 能想到什么, 假如说我们没用Spring, 我们是不是可以调用对应的setter方法给UserDao实例化呢, 唉!, 不错,可以的, 只不过呢,我们现在不用去创建Service的对象再调用sett..方法了,在UserServiceImpl的bean标签中,有一个标签定义属性 也就是<property><bean id="userService" class="priv.zlj.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> property标签:表示配置当前bean的属性 name属性:表示配置哪一个具体的属性 ref属性:表示参照哪一个bean 也就是说呢,咱创建对象的话,人家Spring都给包揽了, 咱就简单配置配置标签就能用, 很便捷,很soEasy~~.
Bean的配置
Bean起别名
还记得我们在上面哪个测试类中, 获取对象的方法吗, getBean("..");
难道说在bean标签中只能通过 id 获取吗? ×
在<bean> 标签中还提供了一个name 也就是定义bean的 别名, 可以定义多个, 使用逗号,分号, 空格 ,都可以(英文状态下)
Bean作用范围配置
名称 : scope
类型 : 属性
所属 : bean标签
功能 : 定义bean的作用范围, 可选范围
~ singleton : 单例(默认)
~ prototype : 非单例
范例 :<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl" scope="prototype" />扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
实际开发中, 绝大部分的Bean 都是单例的, 也就是说绝大部分Bean不需要配置scope属性
Bean的实例化-三种方式
bean是如何创建的?
bean本质就是对象, 创建bean使用构造方法完成
构造方式 [重点]
还记得UserServiceImpl 这个类吗? 当我们在实例化这个类的时候, 一定会用到构造方法吧, 对吧, 那就有人说了, 唉~ 构造方法,我们没有创建阿, 哪里来的构造方法???蒙蔽,, !!!说没有构造方法的童鞋这个时候就可以去再复习Java基础了, 我们是不是有讲过, 当我们没有手动添加一个构造方法的时候, 编译器会自动赠送一个, 空参的构造方法, 那就懂了, 当我们使用bean标签创建对象的时候, 有一个class属性, 为什么要出传递全类名??? 可以想到什么?? 反射!!! 对,咱先不对其底层有过多的研究,到后面, 肯定还是要细细地学地,所以现在前不细细研究,
因为咱上面地IOC和DI案例就是用的构造方法实例化的, 在这, 我们就不粘贴了, 请大家动动你们发财的小手上去翻.
静态工厂方式
实例工厂方式
实现FactoryBean<T>方式
Bean的生命周期 [了解]
- 生命周期 : 从创建到消亡的完整过程
- bean生命周期 : bean从创建到销毁的整体过程
- bean生命周期控制 : 在bean创建后到销毁前做一些事情
Bean声明周期控制(定义方法)
在这里我们发现, init()方法执行了, 但是destory()方法没有执行??? Why? 为啥? 配置也配置了,你init()方法执行了, 我destory()方法难道就不配吗????
解决 :
为什么要替换一下ApplicationContext这个引用为ClassPathXmlApplicationContext呢, 因为ApplicationContext这个接口中没有close()这个方法,所以.....
调用registerShutdownHook这个方法
有一点不同,调用close方法必须在最后面调用否则就会抛出
而调用registerShutdownHook方法在对象的后面哪里都可以调用
Bean声明周期控制(实现接口)
Bean销毁时机
容器关闭时触发bean的销毁
关闭容器的方式 :
手动关闭容器 :
ClassPathXmlApplicationContext 接口中的 close() 方法
注册关闭钩子, 在虚拟机推出前先关闭容器再退出虚拟机
ConfigurableApplicationContext
接口registerShutdownHook()方法
依赖注入(DI配置)
依赖注入俩种方式(重点)
setter方式注入
简单类型
引用类型(常用)
构造方式注入
简单类型
引用类型
参数适配
- 配置中使用 constructor-arg 标签 type 属性设置按形参类型注入
- 配置中使用 constructor-arg 标签 index 属性设置按形参位置注入
依赖注入方式选择
强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
可选依赖使用setter注入进行,灵活性强
Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
自己开发的模块推荐使用setter注入
依赖自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式 :
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
配置中使用bean标签autowire属性设置自动装配的类型
依赖自动装配特征 :
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入
<bean id="bookDao" class="priv.zlj.dao.impl.BookDaoImpl" >
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</list>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="1"/>
<entry key="province" value="2"/>
<entry key="city" value="3"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
time : 2022/12/11 18:00