✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:SSM 框架从入门到精通
✨特色专栏:国学周更-心性养成之路
🥭本文内容:一文吃透 Spring 中的IOC和DI
文章目录
Spring 中 IOC 和 DI
IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。
Spring 中使用的对象都由 IoC 容器管理,不需要我们手动使用 new 运算符创建对象。由 IoC 容器管理的对象称为 Spring Bean,Spring Bean 就是 Java 对象,和使用 new 运算符创建的对象没有区别。
Spring 通过读取 XML 或 Java 注解中的信息来获取哪些对象需要实例化。Spring 提供 2 种不同类型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器
1. BeanFactory 容器
BeanFactory 是最简单的容器,由 org.springframework.beans.factory.BeanFactory 接口定义,采用懒加载(lazy-load),所以容器启动比较快。BeanFactory 提供了容器最基本的功能,配置文件加载时不会创建对象,在获取bean时才会创建对象
为了能够兼容 Spring 集成的第三方框架(如 BeanFactoryAware、InitializingBean、DisposableBean),所以目前仍然保留了该接口。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。BeanFactory 接口有多个实现类 org.springframework.beans.factory.xml.XmlBeanFactory最常见
使用 BeanFactory 需要创建 XmlBeanFactory 类的实例,通过 XmlBeanFactory 类的构造函数来传递 Resource 对象。如下所示。
Resource resource = new ClassPathResource("applicationContext.xml");BeanFactory factory = new XmlBeanFactory(resource);
2. ApplicationContext 容器
ApplicationContext 继承了 BeanFactory 接口,由 org.springframework.context.ApplicationContext 接口定义,对象在启动容器时加载。ApplicationContext 在 BeanFactory 的基础上增加了很多企业级功能,例如 AOP、国际化、事件支持等。
ApplicationContext 接口有两个常用的实现类,具体如下。
【1】ClassPathXmlApplicationContext
该类从类路径 ClassPath 中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);配置文件加载,则创建对象
在上述代码中,configLocation 参数用于指定 Spring 配置文件的名称和位置,如 Beans.xml。
【2】FileSystemXmlApplicationContext
该类从指定的文件系统路径中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
二者的主要区别在于,如果 Bean 的某一个属性没有注入,使用 BeanFacotry 加载后,第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则会在初始化时自检,这样有利于检查所依赖的属性是否注入。
因此,在实际开发中,通常都选择使用 ApplicationContext,只有在系统资源较少时,才考虑使用 BeanFactory。
【3】spring容器加载多个配置文件
- 使用字符串参数,逗号分隔
//加载spring的配置文件 启动spring容器ApplicationContext ac = new ClassPathXmlApplicationContext("config/student.xml","config/springConfig.xml");
- 使用字符串数组
String[] config = {"config/student.xml","config/springConfig.xml"}; //加载spring的配置文件 启动spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext(config);
- 使用导入
//加载spring的配置文件 启动spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("config/applicationContext.xml");
3. Spring Bean定义
由 Spring IoC 容器管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息创建。
可以把 Spring IoC 容器看作是一个大工厂,Bean 相当于工厂的产品,如果希望这个大工厂生产和管理 Bean,则需要告诉容器需要哪些 Bean,以及需要哪种方式装配 Bean。
Spring 配置文件支持两种格式,即 XML 文件格式和 Properties 文件格式。
- Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置。
- XML 配置文件是树形结构,相对于 Properties 文件来说更加灵活。XML 配置文件结构清晰,但是内容比较繁琐,适用于大型复杂的项目。
通常情况下,Spring 的配置文件使用 XML 格式。XML 配置文件的根元素是 ,该元素包含了多个子元素 。每一个 元素都定义了一个 Bean,并描述了该 Bean 如何被装配到 Spring 容器中 元素中可以包含很多属性,其常用属性如下表所示。
属性名称 | 描述 |
---|---|
id | Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。 |
name | name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。 |
class | 该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。 |
scope | 用于设定 Bean 实例的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton |
constructor-arg | 元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型 |
property | 元素的子元素,用于调用 Bean 实例中的 setter 方法来属性赋值,从而完成依赖注入。该元素的 name 属性用于指定 Bean 实例中相应的属性名 |
ref | 和 等元素的子元索,该元素中的 bean 属性用于指定对某个 Bean 实例的引用 |
value | 和 等元素的子元素,用于直接指定一个常量值 |
list | 用于封装 List 或数组类型的依赖注入 |
set | 用于封装 Set 类型的依赖注入 |
map | 用于封装 Map 类型的依赖注入 |
entry | |
init-method | 容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法 |
destroy-method | 容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效 |
lazy-init | 懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效 |
4. IOC创建对象的方式
【1】无参构造器创建对象 (默认)
【2】有参构造创建对象
- 使用下标传递参数
- 使用数据类型传递参数
- 通过属性名传递参数
【3】创建对象时属性的其它注入方式
- set注入
张三 李四 王五 抽烟 喝酒 烫头
java php c# com.mysql.jdbc.Driver jdbc:mysql:///mybatis root rooot
使用set注入,每个属性必须含有对应的set方法,否则无法进行属性的注入
- Spring的依赖注入之p命名空间和c命名空间
p命名空间是set注入的一种快捷实现方式,想要使用p命名空间注入,需要注意一下几点。
- 实体类中必须有set方法;
- 实体类中必须有无参构造器(默认存在);
- 必须导入p命名空间注入方式依赖。
xml依赖代码:
xmlns:p="http://www.springframework.org/schema/p"
导入后即可使用
c命名空间是构造器注入的一种快捷实现方式,想要使用c命名空间,需要注意一下几点。
- 实体类中必须存在有参构造器;
- 必须导入c命名空间注入方式依赖。
xml依赖代码:
xmlns:c="http://www.springframework.org/schema/c"
导入后即可使用
类型转换器的使用:
作用:自定义注入参数和实体类中类型的匹配方式
import org.springframework.core.convert.converter.Converter;public class MyConverter implements Converter { @Override public Date convert(String source) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date parse = simpleDateFormat.parse(source); return parse; } catch (ParseException e) { e.printStackTrace(); } return null; }}
xml文件配置:
5. Bean的自动装配
【1】autowire="byName"在容器的上下文中寻找与类中属性对应的set方法名字相同的id属性值进行装配
【2】autowire="byType"在容器的上下文中寻找与类中属性类型相同的Bean进行装配
【3】使用注解自动装配
- 导入context约束
- 开启注解支持
public class Student { @Value("2021") private String stuNo; @Value("wangwu") private String name; @Value("20") private int age; @Value("2021/12/08") private Date birth; @Autowired private Teacher teacher; @Resource private ClassRoom classRoom; }
获取配置文件中的值
public class Aoo { @Value("${test.boolean}") private Boolean testBoolean; @Value("${test.string}") private String testString; @Value("${test.integer}") private Integer testInteger; @Value("${test.long}") private Long testLong; @Value("${test.float}") private Float testFloat; @Value("${test.double}") private Double testDouble; @Value("#{'${test.array}'.split(',')}") private String[] testArray; @Value("#{'${test.list}'.split(',')}") private List testList; @Value("#{'${test.set}'.split(',')}") private Set testSet; @Value("#{${test.map}}") private Map testMap; }
配置文件 properties
test.boolean=truetest.string=abctest.integer=123test.long=123test.float=1.2345678123456test.double=1.2345678123456test.array=1,3,4,5,6,1,2,3test.list=1,3,4,5,6,1,2,3test.set=1,3,4,5,6,1,2,3test.map={name:"zhangsan", age:18}
6. spring中复杂对象的创建
【1】FactoryBean
public class ConnectionFactoryBean implements FactoryBean { @Override public Connection getObject() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC", "root", "root"); return connection; } @Override public Class> getObjectType() { return Connection.class; } @Override public boolean isSingleton() { return false; }}
xml配置方式:
【2】实例工厂
public class ConnectionFactoryBean { public Connection getConnection() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC&useSSL=false", "root", "root"); return connection; }}
xml配置方式:
【3】静态工厂
public class ConnectionFactoryBean { public static Connection getConnection() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC&useSSL=false", "root", "root"); return connection; }}
xml配置方式:
码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识,点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。
来源地址:https://blog.csdn.net/hh867308122/article/details/129091057