【Spring】一文带你吃透IOC容器技术

news2024/12/27 5:40:11

目录

一、前言

二、IOC容器技术

1、ioc概念

2、DI依赖注入

2.1、构造注入依赖

2.2、setter注入依赖

3、ioc底层实现

4、基于xml配置声明Bean以及使用

4.1、根节点标签beans

4.2、声明Bean

4.3、Bean的使用

5、面向接口编程

5.1、新增接口IOrderService

5.2、OrderServiceImpl实现类

5.3、测试类

6、项目中如何注入Spring容器ApplicationContext

7、总结


一、前言

    Spring 使得 Java 编程对每个人来说都更快更容易更安全。Spring 对速度简单性生产力的关注使其成为世界上最受欢迎的 Java 框架,没有之一。

    我们使用了很多 Spring 框架附带的工具,获得了很多开箱即用的解决方案的好处,并且不用担心编写大量额外的代码ーー所以这确实节省了我们的时间精力,让更多的时间精力放在业务上面。

    Spring 的灵活库深受世界各地开发人员的信任。Spring 每天为数以百万计的终端用户提供令人愉快的体验ーー无论是流媒体电视、在线购物,还是无数其他创新解决方案。Spring 也有来自科技界所有大牌的贡献,包括阿里巴巴亚马逊谷歌微软等等。

    Spring 的灵活而全面的扩展集和第三方库让开发人员可以构建几乎任何想象得到的应用程序。在其核心,spring 框架的控制反转(ioc)和依赖注入(di)特性为一系列广泛的特性和功能提供了基础。无论你是在为网络构建安全的、反应性的、基于云的微服务,还是为企业构建复杂的流式数据流,Spring 都提供了帮助。

二、IOC容器技术

1、ioc概念

Inversion_of_control控制反转:把对象的创建、属性赋值、依赖关系以及对象的生命周期交给Speing容器管理与维护,实现了自动化,不需人工手动管理与维护。

ioc的控制反转:

  • 控制:对象的创建、对象间的依赖关系以及生命周期管理维护
  • 反转:将开发人员管理维护对象的权限交给了容器,目的是实现自动化节省时间精力

而如果不使用Spring的IOC技术,那么开发人员需要人工手动new创建对象、维护对象间的依赖关系以及对象的使用销毁等。光是人工手动就需要时间与精力了,维护销毁上面忘记了处理不妥当将造成不必要的内存消耗资源浪费,甚至内存泄露与溢出

2、DI依赖注入

DI(DependencyInjection)依赖注入:Spring容器在实例化Bean的过程中,使用DI来处理Bean之间的依赖关系。同样依赖也是受Spring管理与维护的,同样需要配置,也是作为单例维护到Spring容器当中,这样就提高资源利用率节约内存开销。

问题来了,有人还是会问什么是依赖或者依赖是什么样子的?依赖注入的方式有哪些?

2.1、构造注入依赖

public class OrderServiceImpl {
    private GoodsService goodsService;

    /**
     * 构造初始化
     * 
     * @param goodsService 商品服务
     */
    OrderServiceImpl(GoodsService goodsService) {
        this.goodsService = goodsService;
    }
    
    public void buy() {
        // 获取商品信息
        String message = this.goodsService.message();
        // 下单......
    }
    
}

class GoodsService {
    
    public String message() {
        return "商品信息";
    }
}

OrderServiceImpl订单服务下单buy()方法中需要调用GoodsService商品服务的message()方法查询获取商品信息,所以OrderServiceImpl依赖GoodsService。你要调用一个类的方法,一般你需要创建这个类的对象,然后把这个对象传递(传参/注入)进来,你就可以使用它的方法了。

2.2、setter注入依赖

import org.springframework.util.ObjectUtils;

/**
 * @author CeaM
 * 2022/12/17 16:19
 **/
public class OrderServiceImpl {
    private GoodsService goodsService;

    /**
     * setter注入
     * 
     * @param goodsService 商品服务
     */
    public void setGoodsService(GoodsService goodsService) {
        this.goodsService = goodsService;
    }

    public void buy() {
        if (ObjectUtils.isEmpty(goodsService)) {
            throw new RuntimeException("商品信息不能为空!!!");
        }
        // 获取商品信息
        String message = this.goodsService.message();
        // 下单......
    }

}

class GoodsService {

    public String message() {
        return "商品信息";
    }
}

这些确实是依赖注入,可能有人情不自禁会问可是为什么呢?为什么需要依赖注入,因为单一职责。每一个类都需要清晰的职责,而不是职责不明确,难以维护。一个Bean类就像一个企业员工,并不是把所有的任务都交给它,这会效率不高甚至有无法完成的风险等,当然如果是你你也不想活活累死。所以企业员工都有自己明确的职责,各司其职,协同配合,使得企业正常稳定运营。同样的,项目就像一个企业,每个Bean都有自己的职责,有的共同完成项目的功能。撒多了。

3、ioc底层实现

 由图可见类还是很多的,划分职责,共同协调配合实现IOC。Spring的IOC实现的两大核心模块就是spring-beansspring-context,而最高层接口就是ApplicationContextBeanFactory。而spring-context,扩展了spring-beans,提供了更加丰富的功能,相对来说spring-context是spring-beans的高层。Spring先初始化IOC容器,以决定使用哪些容器,然后注册Bean定义以及实例化等,维护到容器的缓存当中,底层数据结构基于Map实现缓存。如果是Bean定义,那么keybeanNamevalue是Bean的class全限定类名;如果是Bean实例,那么key也是beanNamevalue就是Bean的实例,底层通过反射获取Bean的class,然后获取其构造器进行实例化的。感兴趣的读者,可以看看笔者Spring家族及微服务系列专栏前面的文章,里面已经详细分析了,这里不会过多赘述。

4、基于xml配置声明Bean以及使用

步骤如下:

  • 创建maven项目。没有安装的需要安装,安装前需要先安装JDK,已安装忽略
  • 引入Spring依赖,在pom.xml加上
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.3.23</version>
            </dependency>
        </dependencies>

  • 定义Bean,即定义类或者定义类及其实现类
  • 创建Spring配置文件,用于声明Bean如何交给Spring容器去创建与管理
  • 使用容器中缓存的Bean,根据依赖倒置原则,一般我们得用高层接口ApplicationContext,调用其getBean()方法根据唯一id(beanName)获取Bean实例。

4.1、根节点标签beans

<?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"  
            xsi:schemaLocation="   
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd">  
     
</beans>
  • 基于xml配置Bean的文件都需要beans根节点,后面的是约束文件,规范如何定义xml配置。
  • beans可见是一个复数,那么它里面就可以声明多个子元素bean。
  • 根节点子元素,不知道大家有没有想到什么数据结构?

4.2、声明Bean

<?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"  
            xsi:schemaLocation="   
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd">  

    <!-- 指定扫描路径 -->
    <context:component-scan base-package="com.ceam.spring"/>
    <context:annotation-config />

    <bean id="orderService" class="com.ceam.spring.service.OrderServiceImpl">
    </bean>       
</beans>
  • context:component-scan:用于指定Spring扫描器将要扫描的路径
  • base-package:Bean所在的基础包名,如:com.ceam.spring
  • bean:用于声明Bean。里面也可以声明属性,那么这时相对属性它就是父节点。
  • id:Bean的全局唯一标识,如果不唯一启动项目就报错,根据id可获取访问Bean。一般最好就是跟class的类名相同,如果是接口与实现类,则id指定接口名。
  • class:全限定类名,即类所在的全部包名+类名

4.3、Bean的使用

package com.ceam.spring;

import com.ceam.spring.service.GoodsService;
import com.ceam.spring.service.OrderServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author CeaM
 * 2022/12/17 20:08
 **/
public class SpringApp {

    public static void main(String[] args) {
        // 1、指定配置文件名称
        String springConfig = "spring-config.xml";
        /*2、
          根据配置文件名称加载类路径(classpath)下的配置文件(放在src/main/resources下);
          Spring底层初始化容器,然后装配实例化Bean;
          ApplicationContext是Spring容器的接口高层,我们应该依赖高层而不是底层
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
        // 3、调用getBean("id"),根据beanName即xml配置文件中的id,从容器中获取bean实例,强制类型转换
        OrderServiceImpl impl = (OrderServiceImpl)applicationContext.getBean("orderService");
        // 创建商品服务,你也可以尝试通过Spring去使用
        GoodsService goodsService = new GoodsService();
        // 4、setter注入
        impl.setGoodsService(goodsService);
        // 5、下订单购买商品
        impl.buy();
    }
}
  1. 指定配置文件名称,如:"spring-config.xml"
  2. 根据配置文件名称加载类路径(classpath)下的配置文件(放在src/main/resources下);Spring底层初始化容器,然后装配实例化Bean;ApplicationContext是Spring容器的接口高层,我们应该依赖高层而不是底层
  3. 调用getBean("id"),根据beanName即xml配置文件中的id,从容器中获取bean实例,返回的是Object类型。故须强制类型转换为OrderServiceImpl,才能调用其方法
  4. 创建商品服务(你也可以尝试通过Spring去使用),setter注入到订单服务
  5. 下订单购买商品

5、面向接口编程

5.1、新增接口IOrderService

package com.ceam.spring.service;

/**
 * @author CeaM
 * 2022/12/17 22:07
 **/
public interface IOrderService {

    /**
     * 模拟查询订单列表
     */
    void listOrders();
}

5.2、OrderServiceImpl实现类

package com.ceam.spring.service;


import org.springframework.util.ObjectUtils;

/**
 * @author CeaM
 * 2022/12/17 16:19
 **/
public class OrderServiceImpl implements IOrderService {
    private GoodsService goodsService;

    /**
     * setter注入
     *
     * @param goodsService 商品服务
     */
    public void setGoodsService(GoodsService goodsService) {
        this.goodsService = goodsService;
    }

    public void buy() {
        if (ObjectUtils.isEmpty(goodsService)) {
            throw new RuntimeException("商品信息不能为空!!!");
        }
        // 获取商品信息
        String message = this.goodsService.message();
        System.out.println("【商品信息】:" + message);
        // 下单......
    }

    @Override
    public void listOrders() {
        System.out.println("查询订单列表");
    }
}

5.3、测试类

public class SpringApp {

    public static void main(String[] args) {
        // 1、指定配置文件名称
        String springConfig = "spring-config.xml";
        /*2、
          根据配置文件名称加载类路径(classpath)下的配置文件(放在src/main/resources下);
          Spring底层初始化容器,然后装配实例化Bean;
          ApplicationContext是Spring容器的接口高层,我们应该依赖高层而不是底层
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
        // 3、调用getBean("id"),根据beanName即xml配置文件中的id,从容器中获取bean实例,强制类型转换
        IOrderService impl = (IOrderService)applicationContext.getBean("orderService");
        // 4、查询订单列表
        impl.listOrders();
    }
}

这些都是我们日常开发当中使用到的,都比较熟悉了吧

6、项目中如何注入Spring容器ApplicationContext

public class DefaultRocketMQListenerContainer implements InitializingBean,
        RocketMQListenerContainer, SmartLifecycle, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

这个是消息中间件RocketMQ中默认监听器容器使用的例子,具体源码分析可以看看我的SpringCloud Alibaba专栏文章。这里就是实现了Spring的ApplicationContextAware接口,实现它的setApplicationContext()方法,即我们所说的setter注入。Spring在初始化DefaultRocketMQListenerContainer过程中就完成依赖的注入。为什么是ApplicationContext,上面我们也说了,根据依赖倒置原则,我们应该依赖高层。

7、总结

本篇文章其实主要讲解的是基于xml配置Bean的实现,这种在早期Spring开发就是这种形式。但是如果随着配置的增多,你会发现实际上也涉及到了人工开发与维护了,所以后面Spring开始了基于注解的配置。

  • IOC的概念与底层实现,DI的概念与举例、构造和setter注入,更多详细分析请看Spring家族及微服务系列专栏。重点
  • ApplicationContextAware的实现与ApplicationContext的注入,重点

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

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

相关文章

非零基础自学Golang 第11章 文件操作 11.2 文件基本操作 11.2.2 文件读取

非零基础自学Golang 文章目录非零基础自学Golang第11章 文件操作11.2 文件基本操作11.2.2 文件读取第11章 文件操作 11.2 文件基本操作 11.2.2 文件读取 想要读取文件可以使用os库中的Read接口&#xff1a; func (f &#xff0a;File) Read(b []byte) (n int, err error)Re…

RCNN网络源码解读(Ⅳ) --- 训练SVM二分类模型的准备过程

目录 1.回忆上一讲及本讲我们要做什么 2.回顾finetune是怎么训练的&#xff08;finetune.py&#xff09; 3. 训练SVM二分类模型 &#xff08;linear_svm.py&#xff09; 3.1 load_data 3.2 custom_classifier_dataset.py 3.3 custom_batch_sampler.py 3.4 hinge_loss 1…

python制作问题搜索解答器,从此学习无忧

前言 大家早好、午好、晚好吖 ❤ ~ 今天博主给大家带来一个问题搜索解答器&#xff01;&#xff01; 需要素材 以及一双慧手和一个灵活的脑子~ 效果展示 代码展示 导入模块 import requests import tkinter as tk from tkinter import ttk import webbrowserdef search(wor…

北京车牌那么难摇为什么还能那么受欢迎?

在北京生活的人来说一块北京车牌真的影响正常生活&#xff0c;特别是这两年的疫情反复...&#xff0c;面对房贷房租&#xff0c;衣食住行&#xff0c;就算外面世界再纷纷扰扰&#xff0c;也要面对...所以在北京生活没有一辆北京车牌汽车真的很麻烦。 对于在北京生活的人来说就…

【C语言刷题】PTA基础编程题目集精选

作者&#xff1a;匿名者Unit 专栏&#xff1a; 《C语言刷题》 目录题目精选6-7 统计某类完全平方数6-9 统计个位数字6-10 阶乘计算升级版6-11 求自定类型元素序列的中位数题目精选 6-7 统计某类完全平方数 我们先看一下题目要求&#xff1a; 根据题目给出的要求&#xff1a…

瑞格科技IPO被终止:曾拟募资5.6亿 江振翔三兄弟为实控人

雷递网 雷建平 12月17日浙江瑞格智能科技股份有限公司&#xff08;简称&#xff1a;“瑞格科技”&#xff09;日前IPO被终止。瑞格科技计划募资5.59亿元&#xff0c;其中&#xff0c;2.55亿元用于年产1000万套汽车配件技改项目&#xff0c;9240万元用于年产500万件智能传感器及…

css深度选择器deep

1.为什么要有deep 1.当我们给组件设置scoped的时候&#xff0c;此时我们组件的css样式只会对自己的内容生效&#xff0c;不会对子组件里面的内容生效。 <style lang"scss" scoped> .login-page {min-height: 100vh;background: url(/assets/login-bg.svg) no-r…

大脑网络的图论分析

利用图论测量大脑结构和功能网络的四个步骤: 定义网络节点——在脑电研究中&#xff0c;电极天然形成节点&#xff1b;在磁共振研究中&#xff0c;可以使用不同的脑图谱作为节点或者基于体素水平进行研究估计节点之间的连接性——结构上&#xff0c;可以由DTI计算两个脑区之间…

一文深度剖析扩散模型究竟学到了什么?

Title: <Diffusion Art or Digital Forgery? Investigating Data Replication in Diffusion Models> Paper: https://arxiv.org/pdf/2212.03860.pdf Github: Just get the point. 文章目录导读技术提升动机贡献背景图像检索与复制检测深度学习中的记忆语言模型中的记忆扩…

Linux Qt连接达梦数据库

最近因为工作需要&#xff0c;需要使用Qt连接达梦数据库&#xff0c;在Linux上比较麻烦&#xff0c;首先需要自己编译UnixODBC和Qt的QODBC库&#xff0c;其次还有各种环境配置。这里在安装好后记录一下&#xff0c;以后找起来方便。 先说下我的电脑是麒麟V10系统飞腾的CPU&…

共享SimpleDateFormat的并发问题

1、问题提出 梳理订单逻辑时发现对日期格式进行format的代码有如下写法 OneDateUtil中定义了一个全局static的SimpleDateFormat对象。SimpleDateFormat对象不是线程安全的&#xff0c;在多线程环境下容易造成数据转换和处理错误。 2、为什么SimpleDateFormat线程不安全 Sim…

[附源码]Node.js计算机毕业设计红色景点自驾游网站管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

MySQL~索引

7、索引 MySQL官方对索引的定义为&#xff1a;索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。 提取句子主干&#xff0c;就可以得到索引的本质&#xff1a;索引是数据结构。 7.1、索引的分类 在一个表中&#xff0c;主键索引只能有一个&#xff0c;唯一…

微机原理与接口技术笔记(持续更新)

文章目录前言储存系统与技术材料高速储存器缓冲储存器&#xff08;Cache&#xff09;材料&#xff0c;局部性&#xff0c;访问方式Cache全相联映射Cache交换与一致性单核CPU一致性处理多核CPU的MESI协议主储存器&#xff08;内存&#xff09;主要技术指标容量带宽内存模组与内存…

机器学习100天(九):009 多项式回归理论

机器学习100天,今天讲的是:多项式回归理论! 在前两期视频我们讲解了简单线性回归理论,并解决了一个房价预测的问题,建立了一个房价与地区人口的线性关系。然而,如果数据的分布不是简单的线性关系,又该怎么做呢? 一、多项式回归 我们来看一个例子,在这个二维平面上,…

【蓝桥杯】砝码称重

3417. 砝码称重 - AcWing题库 题意&#xff1a; 思路回顾&#xff1a; 首先这道题一开始我没想用DP做&#xff0c;看到标签是入门题就没想DP qwq 其实这就是一个普通背包 一开始设计状态设计不出来&#xff0c;刚开始设的是dp[i][j]表示前i个物品能表示j种重量 显然是不行…

计算机毕业设计django基于python商品比价平台

项目介绍 随着计算机技术的发展和网络的普及。采用当前流行的B/S模式以及3层架构的设计思想通过Python技术来开发此系统的目的是建立一个配合网络环境的商品比价系统的平台,这样可以有效地解决数据商品比价系统混乱的局面。 本文首先介绍了商品比价系统的发展背景与发展现状,…

年后面试,给你提6点建议!

你好&#xff0c;我是田哥转眼年底&#xff0c;很大部分人都在观望&#xff0c;甚至已经开始着手准备明年的面试了&#xff0c;不知道屏幕前的你是如何打算的&#xff1f;从现在开始&#xff0c;到明年三月份还有两个多月的时间&#xff0c;时间不多&#xff0c;但也不少了。只…

优秀的后端应该有哪些开发习惯?

见识过各种各样的代码,优秀的、垃圾的、不堪入目的、看了想跑路的等等,所以这篇文章记录一下一个优秀的后端 Java 开发应该有哪些好的开发习惯。 拆分合理的目录结构 受传统的 MVC 模式影响,传统做法大多是几个固定的文件夹 controller、service、mapper、entity,然后无限…

CentOS7 离线部署 PostgreSQL12

CentOS7 离线部署 PostgreSQL12下载资源包部署、启动配置服务创建用户及数据库下载资源包 下载地址 https://www.postgresql.org/download/选择系统 3. 拉到最下边点击direct download 4. 选择需要的版本 5. 点击Avaliable Groups下的链接 6. 下载postgresql*、postgresql*-…