Spring IOC中对象的创建、策略及销毁时机和生命周期详解

 更新时间:2023年08月09日 09:38:50   作者:会洗碗的CV工程师  
这篇文章主要介绍了Spring IOC中对象的创建、策略及销毁时机和生命周期详解,Spring默认使用类的空参构造方法创建bean,假如类没有空参构造方法,将无法完成bean的创建,需要的朋友可以参考下

一、对象的创建方式

Spring会帮助我们创建bean,那么它底层是调用什么方法进行创建的呢?有以下三种方法

  • 使用构造方法
  • 使用工厂类方法
  • 使用工厂类的静态方法

接下来详细讲解这三种方法。

1. 使用构造方法

Spring默认使用类的空参构造方法创建bean,假如类没有空参构造方法,将无法完成bean的创建,接下来我们可以测试一下。

package com.example.dao;
import com.example.pojo.Student;
public class StudentDaoImpl1 implements StudentDao{
    /*public StudentDaoImpl1() {
    }*/
    public StudentDaoImpl1(int a){};
    @Override
    public Student findById(int id){
        return new Student(id,"程序员","北京");
    }
}

错误原因:Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentDao' defined in class path resource [bean.xml]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'int' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

翻译:上下文初始化过程中遇到异常-取消刷新尝试:org.springframework.beans.factory.UnsatisfiedDependencyException:创建类路径资源[bean.xml]中定义的名称为“studentDao”的bean时出错:通过构造函数参数0表示的不满足依赖关系;嵌套异常为org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的类型为“int”的符合条件的bean:应至少有1个符合自动连线候选条件的bean。依赖项注释:{}

其实就是没有空的构造函数,加上一个就好了

2. 使用工厂类方法

Spring可以调用工厂类的方法创建bean:创建工厂类,工厂类提供创建对象的方法,在配置文件中配置创建bean的方式为工厂方式。

工厂类StudentDaoFactory:

package com.example.dao;
public class StudentDaoFactory {
    public StudentDao getStudentDao(){
        return new StudentDaoImpl1(1);
    }
}

bean.xml的配置:

    <!-- id: 工厂对象的id,class:工厂类 -->
    <bean id="studentDaoFactory" class="com.example.dao.StudentDaoFactory" />
    <!-- id:bean对象的id,factory-bean:工厂对象的id,factory-method:工厂方法 -->
    <bean id="studentDao" factory-bean="studentDaoFactory" factory-method="getStudentDao"></bean>

测试方法:

    @Test
    public void t2(){
        // 创建spring容器
        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\JavaProjects\\06SSM_Projects\\springdemo\\spring_ioc1\\src\\main\\resources\\bean.xml");
        // 从容器中获取对象
        StudentDao userDao = ac.getBean("studentDao",StudentDao.class);
        System.out.println(userDao);
        System.out.println(userDao.findById(1));;
    }

测试结果:

OK,确实成功写出来了

3. 使用工厂类的静态方法

Spring可以调用工厂类的静态方法创建bean,创建工厂类,工厂提供创建对象的静态方法,在配置文件中配置创建bean的方式为工厂静态方法。

工厂类StudentDaoFactory2

package com.example.dao;
public class StudentDaoFactory2 {
    public static StudentDao getStudentDao2() {
        return new StudentDaoImpl2();
    }
}

bean.xml的配置

    <!-- id:bean的id class:工厂全类名 factory-method:工厂静态方法 -->
     <bean id="studentDao" class="com.example.dao.StudentDaoFactory2" factory-method="getStudentDao2"/>

都是可以成功运行的。

二、对象的创建策略

scope属性设置对象的创建策略。

Spring通过配置 <bean> 中的 scope 属性设置对象的创建策略,共有两种种创建策略。

1. 单例策略

singleton:单例,默认策略。整个项目只会创建一个对象,通过 <bean> 中的 lazy-init 属性可以设置单例对象的创建时机:lazy-init="false"(默认):立即创建,在容器启动时会创建配置文件中的所有Bean对象。lazy-init="true":延迟创建,第一次使用Bean对象时才会创建。下面测试获取对象后的哈希值是否一样就可以知道是否配置单例策略了

bean.xml的配置

    <bean id="studentDao" class="com.example.dao.StudentDaoImpl2" scope="singleton" lazy-init="true" />

测试方法

    @Test
    public void t3(){
        // 创建Spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 从容器获取对象
        StudentDao studentDao1 = ac.getBean("studentDao",StudentDao.class);
        StudentDao studentDao2 = ac.getBean("studentDao",StudentDao.class);
        StudentDao studentDao3 = ac.getBean("studentDao",StudentDao.class);
        System.out.println(studentDao1.hashCode());
        System.out.println(studentDao2.hashCode());
        System.out.println(studentDao3.hashCode());
    }

运行结果

OK,得到的对象都是同一个哈希值,说明确实是同一个对象也就是说成功配置了单例模式。

2. 多例策略

prototype:多例,每次从容器中获取时都会创建对象。

bean.xml配置

<!-- 配置多例策略 -->
<bean id="studentDao" class="com.itbaizhan.dao.StudentDaoImpl2" scope="prototype"></bean>

测试结果

得到的哈希值不一样,说明得到的是不同的对象,确实是多例策略。

  • request:每次请求创建一个对象,只在web环境有效。
  • session:每次会话创建一个对象,只在web环境有效。
  • gloabal-session:一次集群环境的会话创建一个对象,只在web环境有效。

三、对象的销毁时机

对象的创建策略不同,销毁时机也不同:

  • singleton:对象随着容器的销毁而销毁。
  • prototype:使用JAVA垃圾回收机制销毁对象。
  • request:当处理请求结束,bean实例将被销毁。
  • session:当HTTP Session最终被废弃的时候,bean也会被销毁掉。
  • gloabal-session:集群环境下的session销毁,bean实例也将被销毁。

四、生命周期方法

Bean对象的生命周期包含创建——使用——销毁,Spring可以配置Bean对象在创建和销毁时自动执行的方法:

1. 定义生命周期方法

在StudentDaoImpl2中新增生命周期方法

    // 创建时自动执行的方法
    public void init(){
        System.out.println("使用StudentDaoImpl2创建对象"+this.hashCode());
    }
    // 销毁时自动执行的方法
    public void destroy(){
        System.out.println("销毁StudentDaoImpl2创建的对象"+this.hashCode());
    }

2. 配置生命周期方法

    <!-- init-method:创建对象时执行的方法 destroy-method:销毁对象时执行的方法 -->
    <bean id="studentDao" class="com.itbaizhan.dao.StudentDaoImpl2" scope="singleton" init-method="init" destroy-method="destory"></bean>

3. 测试

测试方法

@Test
public void t3(){
  // 创建Spring容器
  ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
  // 销毁Spring容器,ClassPathXmlApplicationContext才有销毁容器的方法
  ac.close();
}

测试结果

也确实可以

五、获取Bean对象的方式

1. 通过id/name获取

获取对象的时候是这样:

StudentDao studentDao = (StudentDao) ac.getBean("studentDao");

2. 通过类型获取

获取对象的时候是这样:

StudentDao studentDao2 = ac.getBean(StudentDao.class);

不需要进行类型强转

3. 通过类型+id/name获取

虽然使用类型获取不需要强转,但如果在容器中有一个接口的多个实现类对象,则获取时会报错,此时需要使用类型+id/name获取,获取对象是这样:

StudentDao studentDao2 = ac.getBean("studentDao",StudentDao.class);

到此这篇关于Spring IOC中对象的创建、策略及销毁时机和生命周期详解的文章就介绍到这了,更多相关Spring IOC对象策略及生命周期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot导出Excel的四种实现方式

    SpringBoot导出Excel的四种实现方式

    近期接到了一个小需求,要将系统中的数据导出为Excel,且能将Excel数据导入到系统,对于大多数研发人员来说,这算是一个最基本的操作了,本文就给大家总结一下SpringBoot导出Excel的四种实现方式,需要的朋友可以参考下
    2024-01-01
  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Spring Boot 整合 Shiro+Thymeleaf过程解析

    Spring Boot 整合 Shiro+Thymeleaf过程解析

    这篇文章主要介绍了Spring Boot 整合 Shiro+Thymeleaf过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • SpringBoot 项目中创建线程池

    SpringBoot 项目中创建线程池

    这篇文章主要介绍了SpringBoot 项目中创建线程池,文章基于Spring Boot项目创建线程池ThreadPoolExecutor,需要的小伙伴可以参考一下
    2022-04-04
  • java学习粗略路线的方法

    java学习粗略路线的方法

    下面小编就为大家带来一篇java学习粗略路线的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • Apache DolphinScheduler实现自动化打包单机/集群部署详解

    Apache DolphinScheduler实现自动化打包单机/集群部署详解

    这篇文章主要为大家介绍了Apache DolphinScheduler实现自动化打包单机/集群部署详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • MyBatis多表操作查询功能

    MyBatis多表操作查询功能

    这篇文章主要介绍了MyBatis多表操作,包括一对一查询,一对多查询的模型,多对多查询的需求,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • Java生成含字母和数字的6位随机字符串

    Java生成含字母和数字的6位随机字符串

    这篇文章主要为大家详细介绍了Java生成含字母和数字的6位随机字符串的相关资料,供大家参考,感兴趣的朋友可以参考一下
    2016-05-05
  • java线程池使用场景及一些建议

    java线程池使用场景及一些建议

    本文主要介绍了java线程池使用场景及一些建议,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 简单了解redis常见客户端及Sharding机制原理

    简单了解redis常见客户端及Sharding机制原理

    这篇文章主要介绍了简单了解redis常见客户端及Sharding机制原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论