• Spring-IoC(XML配置文件形式)


    目录

    概述

    配置文件加载bean(IoC入门)

    IoC中设置依赖(DI入门)

    Bean的作用范围

    Bean的实例化方式

    方式一:使用空参构造器(默认)

     方式二:静态工厂

    方式三:实例工厂

    方式四:Factory Bean(对"实例工厂的优化")

     Bean的生命周期

    控制生命周期

    关闭IoC容器的方式

     依赖注入的方式

    setter方式注入

    构造器注入

     依赖自动装配


    概述

    IoC(Inversion of control) 控制反转,是一种思想。

    IoC思想:为了解耦,在程序中不直接new获得对象,而是由外部提供对象(控制反转)。如果我们直接通过new的方式获得对象,需要清楚所有的底层对象初始化过程进行依赖处理,才能进行逻辑处理,而通过IoC引入的对象(外部提供),我们通过依赖注入(DI)的方式进行依赖处理就行。

     spring技术对IoC思想进行了实现。称为 IoC容器

    IoC容器从当IoC思想中的"外部",用来负责对象的创建、初始化等一系列工作,在IoC容器中的对象统称为bean。

    DI(Dependency Injection)依赖注入

     在IoC容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

    使用对象不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。

    配置文件加载bean(IoC入门)

    测试用的包结构 

    1.使用spring-IoC我们需要导入坐标:

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-contextartifactId>
    4. <version>5.3.18version>
    5. dependency>

    2.创建配置文件,在配置文件中加载bean

     3.在IoC中创建bean

     4.获取IoC中的bean

    1. public class mainTest {
    2. public static void main(String[] args) {
    3. ApplicationContext context = new ClassPathXmlApplicationContext();
    4. //通过设置的id获取bean
    5. UserDAO userDAO = (UserDAO) context.getBean("userDAO");
    6. //bean调用方法
    7. userDAO.save();
    8. }
    9. }

    IoC中设置依赖(DI入门)

    目录结构 

    userService中引用UserDAO,并且使用其中的方法。

    (使用依赖注入形式,原始是new之后使用new的对象调用其中的方法)

    1.引入 依赖

     

     2.设置set方法(相当于是一个入口)

     

     3.到配置文件中设置依赖映射(解决依赖)

    1. <bean id="userServiceImpl" class="com.mh.service.UserServiceImpl">
    2. <property name="userDAO" ref="userDAO">property>
    3. bean>
    4. <bean id="userDAO" class="com.mh.dao.UserDAOImpl">bean>

    4.测试方法即可。

    Bean的作用范围

     在IoC中定义的bean,默认为单例模式scope:singleton

     设置bean的方式:在 中添加属性scope

    Bean的实例化方式

    方式一:使用空参构造器(默认)

    在上述案例中均使用此方式构造bean,使用了默认的空参构造器。

     方式二:静态工厂

    方式三:实例工厂

    跟静态工厂很相似,实例工厂是非静态的,所以需要先将工厂加载到IoC容器中。 

    方式四:Factory Bean(对"实例工厂的优化")

     

     Bean的生命周期

    提到bean的生命周期,也就是在bean创建时或销毁时做一些事情。

    控制生命周期

    方式一:使用配置(非标准化)

    就是在类中声明两个方法,初始化和销毁的方法,将两个自定义的方法配置到中。

    未控制声明周期时执行

    测试代码

    1. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    2. //测试userDAO方法,无依赖,测试成功
    3. UserDAO userDAO = (UserDAO) context.getBean("userDAO");
    4. userDAO.save();

    执行结果 

     设置声明周期的控制

    在类中声明方法

    1. public class UserDAOImpl implements UserDAO{
    2. @Override
    3. public void save() {
    4. System.out.println("UserDAO...");
    5. }
    6. //自定义初始化和销毁方法
    7. public void init(){
    8. System.out.println("初始化方法加载...");
    9. }
    10. public void destroy(){
    11. System.out.println("销毁方法加载...");
    12. }
    13. }

    将方法加载到配置中

     再次测试执行结果:

     会发现一个问题,两个方法,只有初始化方法执行,销毁的方法并没有生效。

    方式二:使用接口(标准化)

    使用两个接口,实现其中的方法,两个接口分别对应着初始化和销毁的方法。

    1. public class UserDAOImpl implements UserDAO, InitializingBean, DisposableBean {
    2. @Override
    3. public void save() {
    4. System.out.println("UserDAO...");
    5. }
    6. //销毁方法
    7. @Override
    8. public void destroy() throws Exception {
    9. }
    10. //初始化方法(在属性之后执行)
    11. @Override
    12. public void afterPropertiesSet() throws Exception {
    13. }
    14. }

    执行测试方法,和方式一 一样:

     两种方法可以看出,只有初始化方法执行,销毁的方法没有被执行,也就是声明周期并没有在虚拟机关闭前自动的调用销毁方法,所以我们只能手动将IoC容器关闭,才会执行销毁方法。

    关闭IoC容器的方式

    1.手动关闭容器

    具体使用:close()

    测试代码

    1. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    2. //测试userDAO方法,无依赖,测试成功
    3. UserDAO userDAO = (UserDAO) context.getBean("userDAO");
    4. userDAO.save();
    5. //手动关闭容器
    6. context.close();

    测试代码执行结果(销毁方法执行)

    2.注册钩子 

    测试代码 

    1. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    2. UserDAO userDAO = (UserDAO) context.getBean("userDAO");
    3. userDAO.save();
    4. context.registerShutdownHook();

     测试代码执行结果和手动关闭结果一致

    手动关闭和注册钩子的方式说明:手动关闭需要考虑书写的位置,一般写到代码最后,而注册钩子则没有书写位置要求。

     依赖注入的方式

    setter方式注入

    引用数据类型 

    setter注入,就是给需要的依赖设置set方法,包括基本数据类型和引用数据类型。

    依赖:userDAO ,设置set方法

    1. public class UserServiceImpl implements UserService{
    2. //引用数据类型
    3. private UserDAO userDAO;
    4. //设置set方法
    5. public void setUserDAO(UserDAO userDAO) {
    6. this.userDAO = userDAO;
    7. }
    8. @Override
    9. public void save() {
    10. //在其中调用userDAO(依赖)
    11. userDAO.save();
    12. System.out.println("userService...");
    13. }
    14. }

     配置依赖

    1. <bean id="userDAO" class="com.mh.dao.UserDAOImpl">bean>
    2. <bean id="userServiceImpl" class="com.mh.service.UserServiceImpl">
    3. <property name="userDAO" ref="userDAO">property>
    4. bean>

    简单数据类型

     设置简单数据类型依赖,并且设置set方法

    1. public class UserDAOImpl implements UserDAO {
    2. //设置简单数据类型依赖
    3. private String uname;
    4. //设置set方法
    5. public void setUname(String uname) {
    6. this.uname = uname;
    7. }
    8. @Override
    9. public void save() {
    10. System.out.println("UserDAO..." + uname);
    11. }
    12. }

    配置依赖

    1. <bean id="userDAO" class="com.mh.dao.UserDAOImpl">
    2. <property name="uname" value="Tom"/>
    3. bean>

    构造器注入

    类中设置简单数据类型和构造器

    1. public class GoodsDAOImpl implements GoodsDAO {
    2. int num;
    3. public GoodsDAOImpl(int num){
    4. this.num = num;
    5. }
    6. @Override
    7. public void save() {
    8. System.out.println("goods..." + num );
    9. }
    10. }
    1. <bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
    2. <constructor-arg name="num" value="100"/>
    3. bean>

    类型装配

    此方式存在紧耦合(属性名字需要一致),不利于使用。解决方式:使用类型进行装配

    1. <bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
    2. <constructor-arg type="int" value="100"/>
    3. bean>

    此方式解决了名字的耦合问题,但是存在:万一数据类型不唯一的情况就不可用。

    比如存在两个int类型的情况。这种情况下:就可以使用索引进行装配。

    索引装配

    1. <bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
    2. <constructor-arg index="0" value="100"/>
    3. bean>

    依赖注入的方式选择 

     依赖自动装配

    IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

     自动装配的方式:

    1.按类型装配

    2.按名称装配

     自动装配特征

    • 自动装配用于引用类型依赖注入,不能简单类型进行操作。
    • 使用按类型装配时,必须保障容器中相容类型的bean唯一。
    • 使用按名称装配时,必须保障容器中具有指定名称的bean。
    • 自动装配优先级低于setter注入与构造器注入。两者使用可能会发生冲突导致报错。
  • 相关阅读:
    关于rdflib解析三元组介绍
    【安泰ATX-3000】线束测试仪:新能源商用车高压绝缘测试分享
    typescript47-函数之间的类型兼容性
    gd32关于IO引脚配置的一些问题
    JavaSE基础1
    “由于一段 Python 代码,我的号被封了”
    最全HTTP/HTTPS面试题整理(二)
    MySQL的基本操作(超详细)
    java-net-php-python-45ssm校园小商品二手交易系统计算机毕业设计程序
    Prophet模型的简介以及案例分析
  • 原文地址:https://blog.csdn.net/m0_60155232/article/details/127493170