携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情
⭐️前面的话⭐️
✉️坚持和努力一定能换来诗与远方!
💭推荐书籍:📚《王道408》,📚《深入理解 Java 虚拟机-周志明》,📚《Java 核心技术卷》
💬算法刷题:✅力扣🌐牛客网
🎈Github
🎈码云Gitee
三、IoC/DI相关内容
7 IOC相关内容
7.1 bean基础配置
7.1.1 bean基础配置(id与class)
bean标签的功能、使用方式以及id和class属性的作用,我们通过一张图来描述下
# class属性能不能写接口如BookDao的类全名呢?
答案肯定是不行,因为接口是没办法创建对象的。
# 前面提过为bean设置id时,id必须唯一,但是如果由于命名习惯而产生了分歧后,该如何解决?
配置别名
7.1.2 bean的name属性指定别名
<!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
<bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常 NoSuchBeanDefinitionException
7.1.3 bean作用范围scope配置
<!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype-->
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
# 为什么bean默认为单例?
bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
# 哪些bean对象适合交给容器进行管理?
表现层对象
业务层对象
数据层对象
工具对象
# 哪些bean对象不适合交给容器进行管理?
封装实例的域对象,因为会引发线程安全问题,所以不适合。
那么单例 bean是怎么造出来的呢?
7.2 bean实例化
# 在讲解这三种创建方式之前,我们需要先确认一件事:
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。
代码详见 spring_03_bean_instance
7.2.1 方法1:构造方法(常用)
public class BookDaoImpl implements BookDao {
// 类中提供构造函数测试
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
Spring底层用的是反射。
Spring底层使用的是类的无参构造方法。
因为每一个类默认都会提供一个无参构造函数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。
分析Spring的错误信息:错误信息从下往上依次查看,因为上面的错误大都是对下面错误的一个包装,最核心错误是在最下面。
7.2.2 方法2:静态工厂(了解)
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
在spring的配置文件 applicationContext.xml中
<!--方式二:使用静态工厂实例化bean-->
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
这种方式一般是用来兼容早期的一些老系统,所以了解为主。
7.2.3 方法3:使用实例工厂实例化bean(了解)
//实例工厂创建对象
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
配置
<!--方式三:使用实例工厂实例化bean-->
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
实例工厂实例化的方式就已经介绍完了,配置的过程还是比较复杂,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean的方式来简化开发。
7.2.4 方法4:使用FactoryBean实例化bean(务必掌握)
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
// bean类型
public Class<?> getObjectType() {
return UserDao.class;
}
}
配置
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
这种方式在Spring去整合其他框架的时候会被用到,所以这种方式需要大家理解掌握。
总结一下:
- 构造方法(常用)
- 静态工厂(了解)
- 实例工厂(了解)
- FactoryBean(实用)
7.3 bean的生命周期
对于生命周期,我们主要围绕着bean生命周期控制来讲解。
# 生命周期
从创建到消亡的完整过程
# bean生命周期
bean对象从创建到销毁的整体过程。
# bean生命周期控制
在bean创建后到销毁前做一些事情。
添加初始化和销毁方法
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化后对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destroy(){
System.out.println("destroy...");
}
}
配置生命周期
<!--init-method:设置bean初始化生命周期回调函数-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
测试
# 从结果中可以看出,init方法执行了,但是destroy方法却未执行,这是为什么呢?
- Spring的IOC容器是运行在JVM中
- 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行
- main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了
- 所以没有调用对应的destroy方法
# 知道了出现问题的原因,具体该如何解决呢?
- ApplicationContext中没有close方法,需要将ApplicationContext更换成ClassPathXmlApplicationContext,
调用ctx的close()方法
- 调用ctx的registerShutdownHook()方法
在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
public class AppForLifeCycle {
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
//ctx.registerShutdownHook();
//关闭容器
ctx.close();
}
}
# 分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多也比较乱。
# Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-method和 destroy-method
修改BookServiceImpl类,添加两个接口InitializingBean, DisposableBean
并实现接口中的两个方法afterPropertiesSet和destroy
实现2个接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
输出
init...
set .....
service init
book dao save ...
service destroy
destroy...
总结一下:
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(set操作)
4.[ 执行bean初始化方法 ]
使用bean
1.执行业务操作
关闭/销毁容器
1.[ 执行bean销毁方法 ]
8 DI相关内容
接下来就进入第二个大的模块DI依赖注入
# 思考🤔:向一个类中传递数据的方式有几种?
- 普通方法(set方法)
- 构造方法
# 思考🤔:依赖注入描述了在容器中建立bean与bean之间的依赖关系的过程,如果bean运行需要的是数字或字符串呢?
- 引用类型
- 简单类型(基本数据类型与String)
# Spring就是基于上面这些知识点,为我们提供了两种注入方式,分别是:
- setter注入
-简单类型
-引用类型
- 构造器注入
-简单类型
-引用类型
8.1 setter注入 property
注入引用数据类型
步骤1:声明属性并提供setter方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;
//setter注入需要提供要注入对象的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//setter注入需要提供要注入对象的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
步骤2:配置文件中进行注入配置
<!--注入简单类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<!--注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--ref属性:设置注入引用类型bean的id或name-->
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
注入基本数据类型
步骤1:声明属性并提供setter方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
//setter注入需要提供要注入对象的set方法
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
//setter注入需要提供要注入对象的set方法
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
步骤2:配置文件中进行注入配置
<!--注入简单类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--value属性:设置注入简单类型数据值-->
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<!--注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--ref属性:设置注入引用类型bean的id或name-->
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
需要注意的是:
- 对于引用数据类型使用的是<property name="" ref=""/>
- 对于简单数据类型使用的是<property name="" value=""/>
8.2 构造器(构造方法)注入 constructor-arg
构造器注入引用数据类型
构造器注入多个引用数据类型
步骤1:删除setter方法并提供构造方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
步骤2:配置文件中进行配置构造方式注入
<!--解决参数类型重复问题,使用位置解决参数匹配-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
- name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
- ref属性指向的是spring的IOC容器中其他bean对象。
构造器注入多个简单数据类型
步骤1:添加多个简单属性并提供构造方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public BookDaoImpl(String databaseName, int connectionNum) {
this.databaseName = databaseName;
this.connectionNum = connectionNum;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
步骤2:配置完成多个属性构造器注入
<!--
标准书写
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
根据构造方法参数名称注入
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
-->
<!--
解决形参名称的问题,与形参名不耦合
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
根据构造方法参数类型注入
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>-->
<!--解决参数类型重复问题,使用位置解决参数匹配-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--根据构造方法参数位置注入-->
<constructor-arg index="0" value="mysql"/>
<constructor-arg index="1" value="100"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
上面已经完成了构造函数注入的基本使用,但是会存在一些问题:
- 当构造函数中方法的参数名发生变化后,配置文件中的name属性也需要跟着变
- 这两块存在紧耦合,具体该如何解决?
在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家
都以了解为主。
# 方式一:删除name属性,添加type属性,按照类型注入
- 这种方式可以解决构造函数形参名发生变化带来的耦合问题
- 但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现了
# 方式二:删除type属性,添加index属性,按照索引下标注入,下标从0开始
- 这种方式可以解决参数类型重复问题
- 但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题
介绍完两种参数的注入方式,具体我们该如何选择呢?
# 1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 强制依赖指对象在创建的过程中必须要注入指定的参数
# 2.可选依赖使用setter注入进行,灵活性强
- 可选依赖指对象在创建过程中注入的参数可有可无
# 3.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
# 4.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
# 5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
# 6.[ 自己开发的模块推荐使用setter注入 ]
8.3 自动配置 autowire属性
前面花了大量的时间把Spring的注入去学习了下,总结起来就一个字麻烦。
8.3.1 什么是依赖自动装配?
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
8.3.2 自动装配方式有哪些?
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
注意事项:
# 需要注入属性的类中对应属性的setter方法不能省略
# 被注入的对象必须要被Spring的IOC容器管理
# 按照类型在Spring的IOC容器中如果找到多个对象,会报NoUniqueBeanDefinitionException
# 一个类型在IOC中有多个对象,还想要注入成功,这个时候就需要按照名称注入byName
# 按照名称注入中的名称指的是什么
- 对外部类来说,setBookDao方法名,去掉set后首字母小写是其属性名
# 两种方式介绍完后,以后用的更多的是按照类型注入
1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
8.4 集合注入
前面我们已经能完成引用数据类型和简单数据类型的注入,但是还有一种数据类型集合,集合中既可以装简单数据类型也可以装引用数据
类型,对于集合,在Spring中该如何注入呢?
# 先来回顾下,常见的集合类型有哪些?
数组
List
Set
Map
Properties
# 针对不同的集合类型,该如何实现注入呢?
下面的所有配置方式,都是在bookDao的bean标签中进行注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
</bean>
8.4.1 注入数组类型数据
<!--数组注入-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
8.4.2 注入List类型数据
<!--list集合注入-->
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
8.4.3 注入Set类型数据
<!--set集合注入-->
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
8.4.4 注入map类型数据
<!--map集合注入-->
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
8.4.5 注入Properties类型数据
<!--Properties注入-->
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
输出结果
book dao save ...
遍历数组:[100, 200, 300]
遍历List[itcast, itheima, boxuegu, chuanzhihui]
遍历Set[itcast, itheima, boxuegu]
遍历Map{country=china, province=henan, city=kaifeng}
遍历Properties{province=henan, city=kaifeng, country=china}
说明
# property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
# List的底层也是通过数组实现的,所以<list>和<array>标签是可以混用
# 集合中要添加引用类型,只需要把<value>标签改成<ref>标签,这种方式用的比较少
# day02
掌握IOC/DI配置管理第三方bean
掌握IOC/DI的注解开发
掌握IOC/DI注解管理第三方bean
完成Spring与Mybatis及Junit的整合开发
9 IOC/DI配置管理第三方bean
前面所讲的知识点都是基于我们自己写的类,现在如果有需求让我们去管理第三方jar包中的类,该如何管理?
9.1 案例:数据源对象管理
在这一节中,我们将通过一个案例来学习下对于第三方bean该如何进行配置管理。
以后我们会用到很多第三方的bean,本次案例将使用咱们前面提到过的数据源Druid(德鲁伊)和C3P0来配置学习下。
思路分析
# 需求:使用Spring的IOC容器来管理Druid连接池对象
1.使用第三方的技术,需要在pom.xml添加依赖
2.在配置文件中将【第三方的类】制作成一个bean,让IOC容器进行管理
3.数据库连接需要基础的四要素驱动、连接、用户名和密码,【如何注入】到对应的bean中
4.从IOC容器中获取对应的bean对象,将其打印到控制台查看结果
实现Druid的管理
步骤1:导入druid的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
步骤2:配置第三方bean
在applicationContext.xml配置文件中添加DruidDataSource的配置
<!-- 管理DruidDataSource对象-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
步骤3:从IOC容器中获取对应的bean对象
步骤4:运行程序
# 思考🤔
# 第三方的类指的是什么?
DruidDataSource
# 如何注入数据库连接四要素?
setter注入
实现C3P0管理
同上
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="maxPoolSize" value="1000"/>
</bean>
9.2 加载properties文件
# 上节中我们已经完成两个数据源druid和C3P0的配置,但是其中包含了一些问题,我们来分析下:
- 这两个数据源中都使用到了一些固定的常量如数据库连接四要素,把这些值写在Spring的配置文件中不利于后期维护
- 需要将这些值提取到一个外部的properties配置文件中
- Spring框架如何从配置文件中读取属性值来配置就是接下来要解决的问题。
第三方bean属性优化
# 需求:将数据库连接四要素提取到properties配置文件,spring来加载配置信息并使用这些信息来完成属性注入。
1.在resources下创建一个jdbc.properties(文件的名称可以任意)
2.将数据库连接四要素配置到配置文件中
3.在Spring的配置文件中[ 加载properties文件 ]
4.使用加载到的值实现属性注入
其中第3,4步骤是需要大家重点关注,具体是如何实现。
(1)准备properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
(2)在applicationContext.xml中开context命名空间
(3)加载properties配置文件
<context:property-placeholder location="jdbc.properties"/>
(4)完成属性注入
使用 ${key} 来读取properties配置文件中的内容并完成属性注入
<!-- 3.使用属性占位符${}读取properties文件中的属性-->
<!-- 说明:idea自动识别${}加载的属性值,需要手工点击才可以查阅原始书写格式-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
读取单个属性
# 需求:从properties配置文件中读取key为name的值,并将其注入到BookDao中并在save方法中进行打印。
1.在项目中添加BookDao和BookDaoImpl类
2.为BookDaoImpl添加一个name属性并提供setter方法
3.在jdbc.properties中添加数据注入到bookDao中打印方便查询结果
4.在applicationContext.xml添加配置完成配置文件加载、属性注入(${key})
1,2
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println("book dao save ..." + name);
}
}
3
username=root666
4
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
</bean>
10 核心容器
这里所说的核心容器,大家可以把它简单的理解为ApplicationContext,前面虽然已经用到过,但是并没有系统的学习。
接下来咱们从以下几个问题入手来学习下容器的相关知识:
- 如何创建容器?
- 创建好容器后,如何从容器中获取bean对象?
- 容器类的层次结构是什么?
- BeanFactory是什么?
10.1 创建容器
//1.加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从文件系统下加载配置文件
//ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\workspace\spring\spring_10_container\src\main\resources\applicationContext.xml");
10.2 获取bean的3种方式
方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
这种方式存在的问题是每次获取的时候都需要进行类型转换,有没有更简单的方式呢?
方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);
这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。
10.3 容器类层次结构
10.4 BeanFactory
顶级接口
10.5 核心容器总结
容器相关
-
BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
-
ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
-
ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
-
ApplicationContext接口常用初始化类
- ClassPathXmlApplicationContext (常用)
- FileSystemXmlApplicationContext
bean相关
其实整个配置中最常用的就两个属性id和class。
把scope、init-method、destroy-method框起来的原因是,后面注解讲解的时候还会用到,所以大家对这三个属性关注下。