二、IOC 和 DI 入门案例【重点】 1 IOC 入门案例【重点】 问题导入 标签中 id 属性和 class 属性的作用是什么?
1.1 门案例思路分析
管理什么?(Service 与 Dao)
如何将被管理的对象告知 IOC 容器?(配置文件)
被管理的对象交给 IOC 容器,如何获取到 IoC 容器?(接口)
IOC 容器得到后,如何从容器中获取 bean?(接口方法)
使用 Spring 导入哪些坐标?(pom.xml)
1.2 实现步骤 1 2 3 4 【第一步】导入Spring坐标 【第二步】定义Spring管理的类(接口) 【第三步】创建Spring配置文件,配置对应类作为Spring管理的bean对象 【第四步】初始化IOC容器(Spring核心容器/Spring容器),通过容器获取bean对象
1.3 实现代码 【第一步】导入 Spring 坐标
1 2 3 4 5 6 7 8 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.2.10.RELEASE</version > </dependency > </dependencies >
【第二步】定义 Spring 管理的类(接口)
BookDao 接口和 BookDaoImpl 实现类
1 2 3 4 5 6 7 8 9 public interface BookDao { public void save () ; } public class BookDaoImpl implements BookDao { public void save () { System.out.println("book dao save ..." ); } }
BookService 接口和 BookServiceImpl 实现类
1 2 3 4 5 6 7 8 9 10 11 public interface BookService { public void save () ; } public class BookServiceImpl implements BookService { private BookDao bookDao = new BookDaoImpl (); public void save () { System.out.println("book service save ..." ); bookDao.save(); } }
【第三步】创建 Spring 配置文件,配置对应类作为 Spring 管理的 bean 对象
定义 applicationContext.xml 配置文件并配置 BookServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 ="bookService" class ="com.itheima.service.impl.BookServiceImpl" > </bean > </beans >
注意事项:bean 定义时 id 属性在同一个上下文中(IOC 容器中)不能重复
【第四步】初始化 IOC 容器(Spring 核心容器/Spring 容器),通过容器获取 Bean 对象
1 2 3 4 5 6 7 8 9 10 public class App { public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); BookService bookService= (BookService)ctx.getBean("bookService" ); bookService.save(); } }
1.4 运行结果
2 DI 入门案例【重点】 问题导入 标签中 name 属性和 ref 属性的作用是什么?
2.1 DI 入门案例思路分析
基于 IOC 管理 bean
Service 中使用 new 形式创建的 Dao 对象是否保留?(否)
Service 中需要的 Dao 对象如何进入到 Service 中?(提供方法)
Service 与 Dao 间的关系如何描述?(配置)
2.2 实现步骤 1 2 3 【第一步】删除使用new的形式创建对象的代码 【第二步】提供依赖对象对应的setter方法 【第三步】配置service与dao之间的关系
2.3 实现代码 【第一步】删除使用 new 的形式创建对象的代码
1 2 3 4 5 6 7 public class BookServiceImpl implements BookService { private BookDao bookDao; public void save () { System.out.println("book service save ..." ); bookDao.save(); } }
【第二步】提供依赖对象对应的 setter 方法
1 2 3 4 5 6 7 8 9 10 11 public class BookServiceImpl implements BookService { private BookDao bookDao; public void save () { System.out.println("book service save ..." ); bookDao.save(); } public void setBookDao (BookDao bookDao) { this .bookDao = bookDao; } }
【第三步】配置 service 与 dao 之间的关系
在 applicationContext.xml 中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="bookDao" class ="com.itheima.dao.impl.BookDaoImpl" /> <bean id ="bookService" class ="com.itheima.service.impl.BookServiceImpl" > <property name ="bookDao" ref ="bookDao" /> </bean > </beans >
2.4 图解演示
三、Bean 的基础配置 问题导入 问题 1:在标签上如何配置别名? 问题 2:Bean 的默认作用范围是什么?如何修改?
1 Bean 基础配置【重点】 配置说明
代码演示
见《IOC 入门案例》applicationContext.xml 配置
运行结果
见《IOC 入门案例》运行结果
2 Bean 别名配置 配置说明
代码演示
打印结果
3 Bean 作用范围配置【重点】 配置说明
扩展:scope 的取值不仅仅只有 singleton 和 prototype,还有 request、session、application、 websocket ,表示创建出的对象放置在 web 容器(tomcat)对应的位置。比如:request 表示保存到 request 域中。
代码演示
打印结果
最后给大家说明一下:在我们的实际开发当中,绝大部分的 Bean 是单例的,也就是说绝大部分 Bean 不需要配置 scope 属性。
四、Bean 的实例化 问题导入 Bean 的实例化方式有几种?
1 Bean 是如何创建的【理解】 bean 本质上就是对象,创建 bean 使用构造方法完成
2 实例化 Bean 的三种方式 2.1 构造方法方式【重点】
1 2 3 4 5 6 7 8 public class BookDaoImpl implements BookDao { public BookDaoImpl () { System.out.println("book dao constructor is running ...." ); } public void save () { System.out.println("book dao save ..." ); } }
applicationContext.xml 配置
1 2 <bean id ="bookDao" class ="com.itheima.dao.impl.BookDaoImpl" />
1 2 3 4 5 6 7 8 9 public class AppForInstanceBook { public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); BookDao bookDao = (BookDao) ctx.getBean("bookDao" ); bookDao.save(); } }
注意:无参构造方法如果不存在,将抛出异常BeanCreationException
2.2 静态工厂方式
OrderDao 接口和 OrderDaoImpl 实现类
1 2 3 4 5 6 7 8 public interface OrderDao { public void save () ; } public class OrderDaoImpl implements OrderDao { public void save () { System.out.println("order dao save ..." ); } }
1 2 3 4 5 6 7 public class OrderDaoFactory { public static OrderDao getOrderDao () { System.out.println("factory setup...." ); return new OrderDaoImpl (); } }
applicationContext.xml 配置
1 2 <bean id ="orderDao" class ="com.itheima.factory.OrderDaoFactory" factory-method ="getOrderDao" />
1 2 3 4 5 6 7 8 9 public class AppForInstanceOrder { public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); OrderDao orderDao = (OrderDao) ctx.getBean("orderDao" ); orderDao.save(); } }
2.3 实例工厂方式
UserDao 接口和 UserDaoImpl 实现类
1 2 3 4 5 6 7 8 public interface UserDao { public void save () ; } public class UserDaoImpl implements UserDao { public void save () { System.out.println("user dao save ..." ); } }
1 2 3 4 5 6 public class UserDaoFactory { public UserDao getUserDao () { return new UserDaoImpl (); } }
applicationContext.xml 配置
1 2 3 4 <bean id ="userFactory" class ="com.itheima.factory.UserDaoFactory" /> <bean id ="userDao" factory-method ="getUserDao" factory-bean ="userFactory" />
1 2 3 4 5 6 7 8 9 10 11 12 public class AppForInstanceUser { public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); UserDao userDao = (UserDao) ctx.getBean("userDao" ); userDao.save(); } }
2.4 实现 FactoryBean方式【扩展,了解】
定义 UserDaoFactoryBean 实现 FactoryBean
UserDaoFactoryBean 中实例化什么类型的对象泛型就是该类型。
1 2 3 4 5 6 7 8 9 10 11 public class UserDaoFactoryBean implements FactoryBean <UserDao> { public UserDao getObject () throws Exception { return new UserDaoImpl (); } public Class<?> getObjectType() { return UserDao.class; } }
applicationContext.xml 配置
1 2 <bean id ="userDao" class ="com.itheima.factory.UserDaoFactoryBean" />
使用之前的 AppForInstanceUser 测试类去运行看结果就行了。注意配置文件中 id=”userDao”是否重复。
五、Bean 的生命周期【了解】 问题导入 问题 1:多例的 Bean 能够配置并执行销毁的方法? 问题 2:如何做才执行 Bean 销毁的方法?
1 生命周期相关概念介绍
生命周期:从创建到消亡的完整过程
bean 生命周期:bean 从创建到销毁的整体过程
bean 生命周期控制:在 bean 创建后到销毁前做一些事情
2 代码演示 2.1 Bean 生命周期控制
1 2 3 4 5 6 7 8 9 10 11 12 13 public class BookDaoImpl implements BookDao { public void save () { System.out.println("book dao save ..." ); } public void init () { System.out.println("init..." ); } public void destory () { System.out.println("destory..." ); } }
applicationContext.xml 配置
1 2 3 <bean id ="bookDao" class ="com.itheima.dao.impl.BookDaoImpl" init-method ="init" destroy-method ="destory" />
1 2 3 4 5 6 7 8 9 10 public class AppForLifeCycle { public static void main ( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); BookDao bookDao = (BookDao) ctx.getBean("bookDao" ); bookDao.save(); ctx.close(); } }
2.2 Bean 生命周期控制
实现 InitializingBean, DisposableBean 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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" ); } }
测试类代码同《3.2.1 Bean 生命周期控制》中的测试代码
3 Bean 销毁时机
容器关闭前触发 bean 的销毁
关闭容器方式:
手工关闭容器ConfigurableApplicationContext
接口close()
操作
注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机ConfigurableApplicationContext
接口registerShutdownHook()
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 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(); } }
六、依赖注入(DI 配置) 1 依赖注入方式【重点】 问题导入 依赖注入有几种方式?
1.1 依赖注入的两种方式
setter 注入 简单类型引用类型(很常用)
构造器注入 简单类型 引用类型
1.2 setter 方式注入 问题导入 setter 方式注入使用什么子标签?
引用类型 这里蓝线和红线错了,property 中 ref 应该指向 ,name 指向 BookServiceImpl 类中的 setBookDao
简单类型
1.3 构造方式注入 问题导入 构造方式注入使用什么子标签?
引用类型
简单类型
参数适配【了解】
1.4 依赖注入方式选择
强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致 null 对象出现
可选依赖使用 setter 注入进行,灵活性强
Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入
实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入
自己开发的模块推荐使用 setter 注入
2 依赖自动装配【理解】 问题导入 如何配置按照类型自动装配?
2.1 自动装配概念
IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配
自动装配方式 按类型(常用) 按名称 按构造方法 不启用自动装配
2.2 自动装配类型 依赖自动装配
配置中使用 bean 标签 autowire 属性设置自动装配的类型
1 2 <bean id ="bookDao" class ="com.itheima.dao.impl.BookDaoImpl" /> <bean id ="bookService" class ="com.itheima.service.impl.BookServiceImpl" autowire ="byType" />
依赖自动装配特征
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用按类型装配时(byType)必须保障容器中相同类型的 bean 唯一,推荐使用
使用按名称装配时(byName)必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用
自动装配优先级低于 setter 注入与构造器注入,同时出现时自动装配配置失效
3 集合注入 3.1 注入数组类型数据 1 2 3 4 5 6 7 <property name ="array" > <array > <value > 100</value > <value > 200</value > <value > 300</value > </array > </property >
3.2 注入 List 类型数据 1 2 3 4 5 6 7 8 <property name ="list" > <list > <value > itcast</value > <value > itheima</value > <value > boxuegu</value > <value > chuanzhihui</value > </list > </property >
3.3 注入 Set 类型数据 1 2 3 4 5 6 7 8 <property name ="set" > <set > <value > itcast</value > <value > itheima</value > <value > boxuegu</value > <value > boxuegu</value > </set > </property >
3.4 注入 Map 类型数据 1 2 3 4 5 6 7 <property name ="map" > <map > <entry key ="country" value ="china" /> <entry key ="province" value ="henan" /> <entry key ="city" value ="kaifeng" /> </map > </property >
3.5 注入 Properties 类型数据 1 2 3 4 5 6 7 <property name ="properties" > <props > <prop key ="country" > china</prop > <prop key ="province" > henan</prop > <prop key ="city" > kaifeng</prop > </props > </property >
说明:property 标签表示 setter 方式注入,构造方式注入 constructor-arg 标签内部也可以写、、、、标签