Spring |(二)IOC相关内容 | bean

news2025/4/4 19:10:31

文章目录

  • 📚bean基础配置
    • 🐇bean的id和class
    • 🐇bean的name属性
    • 🐇bean作用范围scope配置
    • 🐇bean基础配置小结
  • 📚bean实例化
    • 🐇构造方法实例化(常用)
    • 🐇静态工厂实例化
    • 🐇实例工厂与FactoryBean
  • 📚bean的生命周期
    • 🐇生命周期设置
    • 🐇销毁操作未调用解决方法
    • 🐇Spring提供的生命周期控制接口

学习来源:黑马程序员SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术

📚bean基础配置

🐇bean的id和class

  • id:使用容器可以通过id值获取对应的bean,在一个容器中id值唯一
  • class:bean的类型,即配置的bean的全路径类名
    在这里插入图片描述

🐇bean的name属性

  • name属性,定义bean的别名,可定义多个,使用逗号、分号、空格分隔。
    在这里插入图片描述

  • 配置别名:打开spring的配置文件applicationContext.xml。

    <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>
    
  • 根据名称容器获取bean对象(对应名称必须在spring配置文件中存在)

    public class AppForName {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            //此处根据bean标签的id属性和name属性的任意一个值来获取bean对象
            BookService bookService = (BookService) ctx.getBean("service4");
            bookService.save();
        }
    }
    

🐇bean作用范围scope配置

  • 验证思路:同一个bean获取两次,将对象打印到控制台,看打印出的地址值是否一致。

    BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
    BookDao bookDao2 = (BookDao) ctx.getBean("bookDao");
    System.out.println(bookDao1);
    System.out.println(bookDao2);
    

    打印结果:
    在这里插入图片描述

  • 默认情况下,Spring创建的bean对象都是单例的。

  • 在Spring配置文件中,配置scope属性来实现bean的非单例创建。

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope=""/>
    
    • 将scope设置为singleton
      在这里插入图片描述
    • 将scope设置为prototype
      在这里插入图片描述
  • bean默认为单例? bean为单例是指在Spring的IOC容器中只会有该类的一个对象。这避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高。

  • 线程安全问题?

    • 如果对象是有状态对象,即该对象有成员变量可以用来存储数据,那所有请求线程共用一个bean对象会存在线程安全问题。
    • 如果对象是无状态对象,即该对象没有成员变量进行数据存储的,方法中的局部变量在方法调用完成后会被销毁,不会存在线程安全问题。
  • 表现层对象、业务层对象、数据层对象、工具对象适合交给容器进行管理。

  • 封装实例的域对象,因为会引发线程安全问题,不适合交给容器进行管理。

🐇bean基础配置小结

在这里插入图片描述

📚bean实例化

以下涉及到的project结构如下:
在这里插入图片描述

🐇构造方法实例化(常用)

  • bean本质上就是对象,对象在new的时候会使用构造方法完成,创建bean也是使用构造方法完成的。
  • 步骤1:准备一个BookDao和BookDaoImpl类,即【提供可访问的构造方法】。
    public interface BookDao {
        public void save();
    }
    
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
    
    }
    
  • 步骤2:将类【配置】到Spring容器
    <?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"/>
    
    </beans>
    
  • 步骤3:编写运行程序
    public class AppForInstanceBook {
        public static void main(String[] args) {
            ApplicationContext ctx = new 
                ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            bookDao.save();
        }
    }
    
  • Spring容器在创建对象的时候走的是类的无参构造方法,且底层用的是反射,能访问类中的私有构造方法。真正在使用这种方式的时候,我们什么也不需要做。

🐇静态工厂实例化

  • 步骤1:准备一个OrderDao和OrderDaoImpl类。
    public interface OrderDao {
        public void save();
    }
    
    public class OrderDaoImpl implements OrderDao {
        public void save() {
            System.out.println("order dao save ...");
        }
    }
    
  • 步骤2:创建一个工厂类OrderDaoFactory并提供一个【静态方法】。
    //静态工厂创建对象
    public class OrderDaoFactory {
        public static OrderDao getOrderDao(){
            return new OrderDaoImpl();
        }
    }
    
  • 步骤3:在spring的【配置】文件application.properties中添加以下内容↓
    <!--方式二-->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
    
    在这里插入图片描述
  • 步骤4:在AppForInstanceOrder运行类,使用从IOC容器中获取bean的方法进行运行测试
    public class AppForInstanceOrder {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
            orderDao.save();
        }
    }
    

  • 静态工厂方法的意义?
    • 主要的原因是在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少(直接new对象的方式就无法添加其他的业务内容),比如:
      public class OrderDaoFactory {
          public static OrderDao getOrderDao(){
              System.out.println("factory setup....");//模拟必要的业务操作
              return new OrderDaoImpl();
          }
      }
      
  • 静态工厂实例化一般是用来兼容早期的一些老系统,所以了解为主

🐇实例工厂与FactoryBean

  • 步骤1:准备一个UserDao和UserDaoImpl类。
    public interface UserDao {
        public void save();
    }
    
    public class UserDaoImpl implements UserDao {
    
        public void save() {
            System.out.println("user dao save ...");
        }
    }
    
  • 步骤2:创建一个【实例工厂】类OrderDaoFactory并提供一个普通方法(注意此处和静态工厂的工厂类不一样的是不是静态方法)。
    public class UserDaoFactory {
        public UserDao getUserDao(){
            return new UserDaoImpl();
        }
    }
    
  • 步骤3:在spring的【配置】文件中添加以下内容↓
    <!--方式三-->
    <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
    
    在这里插入图片描述
  • 步骤4:在AppForInstanceUser运行类,使用从IOC容器中获取bean的方法进行运行测试。
    public class AppForInstanceUser {
        public static void main(String[] args) {
            ApplicationContext ctx = new 
                ClassPathXmlApplicationContext("applicationContext.xml");
            UserDao userDao = (UserDao) ctx.getBean("userDao");
            userDao.save();
        }
    }
    

  • 以上就是实例工厂实例化的方式,Spring为了简化这种配置方式提供了一种叫FactoryBean的方式来简化开发。
    在这里插入图片描述

  • 步骤1:【创建一个UserDaoFactoryBean的类】,【实现FactoryBean接口】,重写接口的方法。

    public class UserDaoFactoryBean implements FactoryBean<UserDao> {
        //【代替】原始实例工厂中创建对象的方法
        public UserDao getObject() throws Exception {
            return new UserDaoImpl();
        }
        //返回所创建类的Class对象
        public Class<?> getObjectType() {
            return UserDao.class;
        }
    }
    
    • 这里造出的对象【默认是单例】的,如果要改成非单例,则加上下
      public boolean isSingleton() {
          return false;
      }
      
  • 步骤2:在Spring的配置文件中进行配置。

    <!--方式四-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
    
  • 步骤3:AppForInstanceUser运行类不用做任何修改,直接运行。


在这里插入图片描述

📚bean的生命周期

⭐️下述内容涉及到的环境配置↓
在这里插入图片描述

  1. 项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类。
    public interface BookDao {
        public void save();
    }
    
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
    }
    
    public interface BookService {
        public void save();
    }
    
    public class BookServiceImpl implements BookService{
        private BookDao bookDao;
    
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    
  2. resources下提供spring的配置文件。
    <?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"/>
    </beans>
    
  3. 编写AppForLifeCycle运行类,加载Spring的IOC容器,并从中获取对应的bean对象。
    public class AppForLifeCycle {
        public static void main( String[] args ) {
            ApplicationContext ctx = new 
                ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            bookDao.save();
        }
    }
    

🐇生命周期设置

  • 生命周期:从创建到消亡的完整过程。
  • 在上面这个环境中来为BookDao添加生命周期的控制方法,具体的控制有两个阶段:
    • bean创建之后,想要添加内容,比如用来初始化需要用到资源。
    • bean销毁之前,想要添加内容,比如用来释放用到的资源。
  • 步骤1:添加初始化和销毁方法。在BooDaoImpl类中分别添加两个方法(方法名任意)。
    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 destory(){
            System.out.println("destory...");
        }
    }
    
  • 步骤2:配置生命周期。
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
    
  • 步骤3:AppForLifeCycle.java运行。
    public class AppForLifeCycle {
        public static void main( String[] args ) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            bookDao.save();
        }
    }
    
  • 运行AppForLifeCycle打印结果为:
    在这里插入图片描述
  • init方法执行了,但是destroy方法却未执行?
    • Spring的IOC容器是运行在JVM中。
    • 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行。
    • main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。

🐇销毁操作未调用解决方法

  • 方法一】:close()关闭容器

    public class AppForLifeCycle {
        public static void main( String[] args ) {
        	//ApplicationContext中没有close方法,将ApplicationContext更换成ClassPathXmlApplicationContext
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            bookDao.save();
            //关闭容器(这句话一出现就直接暴力关闭)
            ctx.close();
        }
    }
    

    在这里插入图片描述

  • 方法二】:注册钩子关闭容器,registerShutdownHook()。在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器。

    public class AppForLifeCycle {
        public static void main( String[] args ) {
        	//registerShutdownHook在ApplicationContext中也没有
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器(这句代码可以往后放,位置放哪不影响)
            ctx.registerShutdownHook();
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            bookDao.save();
        }
    }
    

    在这里插入图片描述

  • 👀比较上述两种方法

    • 相同点:这两种都能用来关闭容器。
    • 不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。

🐇Spring提供的生命周期控制接口

  • Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-methoddestroy-method
  • 在BookServiceImpl完成这两个接口的使用:修改BookServiceImpl类,添加两个接口InitializingBeanDisposableBean并实现接口中的两个方法afterPropertiesSetdestroy
    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
        private BookDao bookDao;
        public void setBookDao(BookDao bookDao) {
            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");
        }
    }
    
  • 重新运行AppForLifeCycle类↓
    在这里插入图片描述

⭐️小细节

  • 对于InitializingBean接口中的afterPropertiesSet方法,翻译过来为属性设置之后,对于BookServiceImpl来说,bookDao是它的一个属性,setBookDao方法是Spring的IOC容器为其注入属性的方法。
  • 思考:afterPropertiesSet和setBookDao谁先执行?
    • 验证——在setBookDao方法中添加一句话↓
      public void setBookDao(BookDao bookDao) {
          System.out.println("set .....");
          this.bookDao = bookDao;
      }
      
    • 重新运行AppForLifeCycle,打印结果如下↓
      在这里插入图片描述
    • 所以初始化方法会在类中属性设置之后执行。

⭐️对于bean的生命周期控制在bean的整个生命周期中所处的位置如下
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2246045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ffmpeg视频滤镜:替换部分帧-freezeframes

滤镜描述 freezeframes 官网地址 > FFmpeg Filters Documentation 这个滤镜接收两个输入&#xff0c;然后会将第一个视频中的部分帧替换为第二个视频的某一帧。 滤镜使用 参数 freezeframes AVOptions:first <int64> ..FV....... set first fra…

Ubuntu24虚拟机-gnome-boxes

推荐使用gnome-boxes&#xff0c; virtualbox构建失败&#xff0c;multipass需要开启防火墙 sudo apt install gnome-boxes创建完毕&#xff5e;

Vscode写markdown快速插入python代码

如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…

docker搭建私有仓库,实现镜像的推送和拉取

1.拉取docker仓库镜像 docker pull registry 2.启动registry容器 docker run -d registry 3.查看当前仓库中存在的镜像&#xff08;一&#xff09; curl -XGET http://192.168.111.162: 5000/v2/_catalog 192.168.111.162 部署docker仓库宿主机的ip 5000 部署docker仓库映射到宿…

基于docker进行任意项目灵活发布

引言 不管是java还是python程序等&#xff0c;使用docker发布的优势有以下几点&#xff1a; 易于维护。直接docker命令进行管理&#xff0c;如docker stop、docker start等&#xff0c;快速方便无需各种进程查询关闭。环境隔离。项目代码任何依赖或设置都可以基本独立&#x…

点餐管理系统设计与实现(Java+SpringBoot+MySql)

目录 第1章 绪论 1.1选题动因 1.2目的和意义 1.3论文结构安排 第2章 开发环境与技术 2.1 MySQL数据库 2.2 Tomcat 介绍 2.3 vue技术 2.4 SpringBoot框架 第3章 系统分析 3.1可行性分析 3.1.1操作可行性分析 3.1.2经济可行性分析 3.1.3技术可行性分析 3.2系统流程…

特征交叉-MaskNet文章总结代码实现

MaskNet 这个模型是微博21年提出的&#xff0c;23年twitter(X)开源的推荐系统排序模块使用的backbone结构。 核心思想是认为DNN为主的特征交叉是addictive&#xff0c;交叉效率不高&#xff1b;所以设计了一种multiplicatvie的特征交叉 如何设计muliplicative特征交叉呢&#x…

(7) 探索Python函数的无限可能:从递归到Lambda的奇妙之旅

欢迎进入Python编程的奇幻世界!在这个课程中,我们将一起探索编程的乐趣,通过生动有趣的方式,培养编程的逻辑思维和创造力,该课程适合有一定基础的中学及以上学生及成年人。 以下是我们课程的大纲: 【Python:趣味编程,探索未来】 目录 1. 前言2. 认识我们的“魔法咒语”…

算法日记 32 day 动态规划(完全背包)

同样是背包问题&#xff0c;但01背包和完全背包是两个类型的问题。 完全背包&#xff1a; 完全背包与01背包的区别在于物品的个数是否是无限的。除此之外&#xff0c;在解决01背包的时候dp的背包遍历的顺利是倒序&#xff0c;为的是保证物品只被添加一次&#xff0c;而完全背包…

实用功能,觊觎(Edge)浏览器的内置截(长)图功能

Edge浏览器内置截图功能 近年来&#xff0c;Edge浏览器不断更新和完善&#xff0c;也提供了长截图功能。在Edge中&#xff0c;只需点击右上角的“...”&#xff0c;然后选择“网页捕获”->“捕获整页”&#xff0c;即可实现长截图。这一功能的简单易用&#xff0c;使其成为…

计算机网络:应用层知识点概述及习题

网课资源&#xff1a; 湖科大教书匠 1、概述 习题1 1 在计算机网络体系结构中&#xff0c;应用层的主要功能是 A. 实现进程之间基于网络的通信 B. 通过进程之间的交互来实现特定网络应用 C. 实现分组在多个网络上传输 D. 透明传输比特流 2 以下不属于TCP/IP体系结构应用层范畴…

【LSTM实战】跨越千年,赋诗成文:用LSTM重现唐诗的韵律与情感

本文将介绍如何使用LSTM训练一个能够创作诗歌的模型。为了训练出效果优秀的模型&#xff0c;我整理了来自网络的4万首诗歌数据集。我们的模型可以直接使用预先训练好的参数&#xff0c;这意味着您无需从头开始训练&#xff0c;即可在自己的电脑上体验AI作诗的乐趣。我已经为您准…

鸿蒙网络编程系列50-仓颉版TCP回声服务器示例

1. TCP服务端简介 TCP服务端是基于TCP协议构建的一种网络服务模式&#xff0c;它为HTTP&#xff08;超文本传输协议&#xff09;、SMTP&#xff08;简单邮件传输协议&#xff09;等高层协议的应用程序提供了可靠的底层支持。在TCP服务端中&#xff0c;服务器启动后会监听一个或…

基于 SpringBoot 的作业管理系统【附源码】

基于 SpringBoot 的作业管理系统 效果如下&#xff1a; 系统注册页面 学生管理页面 作业管理页面 作业提交页面 系统管理员主页面 研究背景 随着社会的快速发展&#xff0c;信息技术的广泛应用已经渗透到各个行业。在教育领域&#xff0c;课程作业管理是学校教学活动中的重要…

怎么只提取视频中的声音?从视频中提取纯音频技巧

在数字媒体的广泛应用中&#xff0c;提取视频中的声音已成为一项常见且重要的操作。无论是为了学习、娱乐、创作还是法律用途&#xff0c;提取声音都能为我们带来诸多便利。怎么只提取视频中的声音&#xff1f;本文将详细介绍提取声音的原因、工具、方法以及注意事项。 一、为什…

Java多态的优势和弊端

1. public class text {public static void main(String[] args) {animal dnew dog();d.eat();// dog a (dog) d;//类似强制转换//a.lookhome();/* if(d instanceof dog){dog a(dog)d;a.lookhome();}else if(d instanceof cat){cat c(cat) d;c.work();}else{System.out.print…

FPGA 14 ,硬件开发板分类详解,FPGA开发板与普通开发板烧录的区别

目录 前言 在嵌入式系统开发中&#xff0c;硬件开发板是工程师常用的工具之一。不同类型的开发板有不同的特点和用途&#xff0c;其中最常见的两大类是普通开发板和FPGA开发板。这里分享记录&#xff0c;这两类开发板的分类&#xff0c;并深入探讨它们在烧录过程中的具体区别…

冲破AI 浪潮冲击下的 迷茫与焦虑

在这个科技日新月异的时代&#xff0c;人工智能如汹涌浪潮般席卷而来&#xff0c;不断改变我们的生活。你是否对 AI 充满好奇&#xff0c;却不知它将如何改变你的工作与生活&#xff1f;又是否会在 AI 浪潮的冲击下陷入迷茫与焦虑&#xff1f;《AI 时代&#xff1a;弯道超车新思…

时序论文23|ICML24谷歌开源零样本时序大模型TimesFM

论文标题&#xff1a;A DECODER - ONLY FOUNDATION MODEL FOR TIME - SERIES FORECASTING 论文链接&#xff1a;https://arxiv.org/abs/2310.10688 论文链接&#xff1a;https://github.com/google-research/timesfm 前言 谷歌这篇时间序列大模型很早之前就在关注&#xff…

Redis的基本使用命令(GET,SET,KEYS,EXISTS,DEL,EXPIRE,TTL,TYPE)

目录 SET GET KEYS EXISTS DEL EXPIRE TTL redis中的过期策略是怎么实现的&#xff08;面试&#xff09; 上文介绍reids的安装以及基本概念&#xff0c;本章节主要介绍 Redis的基本使用命令的使用 Redis 是一个基于键值对&#xff08;KEY - VALUE&#xff09;存储的…