Spring
- Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%
- 专业角度
- 简化开发:降低企业级开发的复杂性
- 框架整合:高效整合其他技术,提高企业级应用开发与运行效率
初识Spring
了解Spring家族
- Spring官网:https://spring.io/
- Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能
- 重点学习
- Spring Framework
- Spring Boot
- Spring Cloud
Spring Framework
Spring Framework系统架构
- SpringFramework是Spring生态圈中最基础的项目,是其他项目的根基
Spring Framework系统架构图:
核心概念
- IoC/DI
- IoC(InversionofControl)控制反转
- 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
- Spring技术对Ioc思想进行了实现
- Spring提供了一个容器,称为Ioc容器,用来充当Ioc思想中的"外部”
- Ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在Ioc容器中统称为Bean
- DI(DependencyInjection)依赖注入
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
- 目的:充分解耦
- 使用Ioc容器管理bean(IoC)
- 在Ioc容器内将有依赖关系的bean进行关系绑定(DI)
IoC入门
1、利用Maven导入Spring的坐标 spring-context
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.6</version>
</dependency>
2、创建配置文件:在 resources
目录下创建 applicationContext.xml
文件。
3、配置bean
# bean标签标识配置bean
# id属性表示bean的名字
# class属性表示bean的定义类型
<bean id="" class=""></bean>
# 注意:bean定义时id属性在同一个上下文中不能重复
4、获取Ioc容器
public static void main(String args[]){
//获取IoC容器
//ApplicationContext是一个接口,我们new一个它的实现对象
//参数是我们的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext
("applicationContext.xml");
//获取bean
//xml文件下配置bean的id名
BookService bs = ctx.getBean("bookService");
//这时候就获取到Ioc容器中bean的对象了
}
DI入门
- 基于Ioc管理bean
- 通过配置进行依赖注入
<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>
<bean id="Service" class="com.fyislo.service.impl.Service">
# property标签表示配置当前bean的属性
# name属性表示我们配给谁?(属性名称)
# ref属性表示我们要把谁给对方(bean的id属性)
<property name="dao" ref="Dao"/>
</bean>
Bean
Bean的配置
使用 name
属性,可以给bean配置多个别名。多个别名之间可以用逗号,分号,空格分隔。
<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>
# name属性可以给bean配置多个别名。多个别名之间可以用逗号,分号,空格分隔。
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service">
<property name="dao" ref="Dao"/>
</bean>
注:获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常 NoSuchBeanDefinitionExceptionNoSuchBeanDefinitionException: Nobeannamed'bookServiceImpl'available
bean的作用范围
Spring给我们创建的bean默认是单例的。
如果需要非单例的bean,则需要在配置文件 <bean>
的标签中添加一个属性: scope
- scoper
- singleton:单例(默认)
- prototype:非单例
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service" scope="prototype">
<property name="dao" ref="Dao"/>
</bean>
- 适合交给容器进行管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
- 不适合交给容器进行管理的bean
- 封装实体类的域对象
bean的实例化
1、使用构造方法完成创建bean(无参构造)
- bean本质上就是对象
- 无参构造如果不存在,将抛出异常
BeanCreationException
2、通过静态工厂创建bean(了解)
通过 class
属性告诉工厂类,在通过factory-method
属性告诉Spring工厂里面的哪个方法是造对象的。
<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getorderDad"/>
3、实例工厂创建bean
- 先配置工厂的bean
- 通过
factory-bean
指定实例工厂的bean - 通过
factory-method
指定造对象的方法
<bean id="userFactory" class="factory.UserDaoFactory"/>
<bean id="orderDao" factory-method="getuserDao" factory-bean="userFactory"/>
4、使用 FactoryBean<T>
实例化
实现接口中的两个方法。
public class UserDaoFactoryBean implements FactoryBean<UserDao>{
//代替原始实例工厂中创建对象的方法
//得到bean的实例
public UserDao getobject() throws Exception{
return new UserDaoImpl();
}
//得到bean的类型
public Class<?> getobjectType(){
//返回创建对象的字节码文件
return UserDao.class;
}
//设置该bean是单例还是非单例的
//默认可以不写该方法
public boolean isSingleton(){
//返回true:单例
//返回false:非单例
return true;
}
}
这时候配置就很简便了
<bean id="userDao" class="factory.UserDaoFactoryBean"/>
bean的生命周期
- 生命周期:从创建到消亡的完整过程
- bean生命周期:bean从创建到销毁的整体过程
- bean生命周期控制:在bean创建后到销毁前做一些事情
在<bean>
标签中init-method
属性可以指定一个方法,在bean创建前运行一个方法。
在 <bean>
标签中 destroy-method
属性可以指定一个方法,在bean销毁前运行的一个方法。
<bean id="" class="" init-method="init" destroy-method="destory"/>
关闭容器
public static void main(String args[]){
//获取IoC容器
//ApplicationContext是一个接口,但是它没有close()方法。
//ClassPathXmlApplicationContext是它的实现类,有close()方法。
ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext
("applicationContext.xml");
//方法一:直接关闭容器
ctx.close();
//方法二:注册关闭钩子,在任何时间注册都可以。
//作用:在虚拟机退出之前,把容器关完了再退出
ctx.registerShutdownHook();
}
使用Spring接口来控制生命周期(这样便不用去xml文件中指定控制生命周期的方法)
实现 InitializingBean
和 DisposableBean
两个接口
public class Service implements InitializingBean, DisposableBean{
public void afterPropertiesSet() throws Exception{
//设置属性之后执行该方法
}
public void destroy() throws Exception{
//
}
}
Bean在初始化过程中经历的阶段
- 初始化容器
- 创建对象(内存分配)
- 执行构造方法
- 执行属性注入(set方法)
- 执行bean初始化方法
- 使用bean
- 执行业务操作
- 关闭/销毁容器
- 执行bean销毁方法
bean销毁时机
- 容器关闭前出发bean的销毁
- 关闭容器方式:
- 手动关闭容器
- ConfigurableApplicationContext接口close()操作
- 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
- ConfigurableApplicationContext接口registerShutdownHook()操作
- 手动关闭容器
bean相关属性
依赖注入
- 依赖注入的两种方式
- 普通方法(set方法)
- 构造方法
- 依赖注入的两种类型
- 引用类型
- 简单类型(基本数据类型和String)
- 依赖注入方式
- setter注入
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
- setter注入
setter方式注入
1、setter方式注入引用类型,在DI入门已有提过。
在xml文件中配置 <bean>
标签,并在其中配置 <property>
标签即可
2、setter方式注入简单类型
<bean id="Service" class="com.fyislo.service.impl.Service">
# property标签表示配置当前bean的属性
# name属性表示我们配给谁?(属性名称)
# 只需要把ref属性替换成value属性,即可完成简单类型的注入
<property name="int" value="123"/>
<property name="string" value="name"/>
</bean>
构造器注入
1、构造器注入引用类型
将setter注入的set方法更换为有参构造即可,在xml的配置有所改变,如下:
<bean id="Service" class="com.fyislo.service.impl.Service">
# 只需把property标签更换为constructor-arg标签即可
<constructor-arg name="形参的名称1" ref=""/>
<constructor-arg name="形参的名称2" ref=""/>
</bean>
2、构造器注入简单类型
# 标准写法:有指定形参的名称
<bean id="Service" class="com.fyislo.service.impl.Service">
# 只需把constructor-arg标签的ref更换为value即可
<constructor-arg name="形参的名称1" value=""/>
<constructor-arg name="形参的名称2" value=""/>
</bean>
# 解决形参名称耦合的问题
<bean id="Service" class="com.fyislo.service.impl.Service">
# 不使用name指定形参名称,使用type指定形参类型
<constructor-arg type="int" value=""/>
<constructor-arg type="java.lang.String" value=""/>
</bean>
# 解决参数类型重复问题,使用位置解决参数匹配
<bean id="Service" class="com.fyislo.service.impl.Service">
# 使用index指定参数位置
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value=""/>
</bean>
依赖注入方式选择
- 制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- .可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
依赖自动装配
- IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
- 自动装配的方式
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
前提:想要自动装配,要提供set方法,xml配置文件如下:
- autowire可选值
- byType:按类型
- byName:按名称
# 自动装配,使用aotuwire属性
# 该类型的bean对象在配置文件中必须是唯一的
# 不唯一,它怎么知道给你注入哪一个?
<bean id="" class="" autowire="byType"/>
- 依赖自动装配特征
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入
<bean id="" class="">
<property name="array">
<array>
<value>100</value>
<value>30</value>
<ref bean="beanId"/> # 引用类型
</array>
</property>
<property name="list">
<list>
<value>adjkl</value>
<value>30</value>
</list>
</property>
<property name="list">
<set>
<value>adjkl</value>
<value>30</value>
</set>
</property>
<property name="list">
<map>
<entry key="name" value="zhangsan"/>
<entry key="" value=""/>
</map>
</property>
<property name="properties">
<props>
<prop key="key">value</prop>
<prop key="key">value</prop>
</props>
</property>
</bean>
加载properties文件
- 开启context命名空间
- 使用context空间加载properties文件(加载的文件从resources目录中寻找)
- 使用属性占位符:${}读取properties文件中的属性
<?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"
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,把两行末尾的beans更换为context
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
# 1.开启context命名空间
2.使用context空间加载properties文件(加载的文件从resources目录中寻找)
# 3. 使用属性占位符:${}读取properties文件中的属性
<context:property-placeholder location="resources目录下的properties文件"/>
<bean id="service" class=
"com.fyislo.service.Impl.BookServiecImpl">
<property name="url" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
</bean>
</beans>
加载properties文件
依赖注入相关
容器
创建容器
1、加载类路径下的配置文件
//加载类路径下的配置文件
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
2、从文件系统下加载配置文件
//从文件系统下加载配置文件
ApplicationContext act = new FileSystemXmlApplicationContext("C:\software\project\JavaProject\JavaStudy\src\main\resources\applicationContext.xml");
加载bean的方式
# 根据名称获取bean,需要强转
BookService bookService = (BookService) act.getBean("service");
# 根据名称获取bean,不需要强转
BookService bookService = act.getBean("service",BookService.class);
# 根据类型获取bean
BookService bookService = act.getBean(BookService.class);
# 加载多个配置文件
ApplicationContext act = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
ApplicationContext
的顶层接口是 BeanFactory
,它也可以创建IoC容器,但存在局限性。
ApplicationContext
和BeanFactory
的区别- 它们加载bean的时机不同
ApplicationContext
是启动容器后立即加载BeanFactory
是延迟加载
- 它们加载bean的时机不同
如果需要 ApplicationContext
完成延时加载,可以给 bean
标签添加一个属性 lazy-init="true"
免责声明:此片文章是个人学习笔记,存在借鉴,若有冒犯或侵权,联系可删除。
标签:容器,Spring,配置,加载,bean,相关,属性,注入 From: https://www.cnblogs.com/fyislo/p/18169505