聊聊Spring的IOC以及JVM的类加载

简介: 聊聊Spring的IOC以及JVM的类加载

面试官看着应聘者,轻轻地说出了这句话 “小伙子,看你简历不错,那么,你是否能聊一下Spring的IOC”

应聘者,看了下面试官,“嗯,IOC,称为控制反转,又叫DI 依赖注入”

面试官追问,“详细聊聊吧”

应聘者,焦虑的磕磕巴巴的说了不着四六的话,面试题简单的背了下名字,但是解释清楚就做不到了。


写在前面

一个面试场景开端,描述了一个尴尬的面试。

其实,概念就是概念,无非是抽象出来的理论,我们要知其然,还要能知其所以然。因此,我们要好好弄清楚到底是什么意思。

好多时候,大家都只是在死读书,但是没有深入内涵,其实是有很大的风险的,今天我们就来聊一下常见的两个面试题。

注:也是记录下,面试被问到这两个问题,我是如何作答的。


IOC概念

IOC,本来是老外搞出来的一个词汇,人家英文的描述是Inversion of Control,中文翻译呢是,控制反转。其实我觉得大多数人都是被这个词给坑了。

举个例子,有一个绑架案。说绑匪绑架了个一个千金小姐,需要小姐家人花钱赎身。在这个场景中,绑匪是控制着,控制着千金小姐的身家性命。但是呢,由于这个千金小姐,比较厉害,会武术。俗话说,女人会武术,神仙挡不住。那,咔咔,三下五除二,解决了绑匪。把所有的绑匪关入囚牢,等待官差的到来。那么,此时是不是控制发生了反转。由被控方,变成了控制方。整个过程,存在的交互,只是绑匪和千金小姐。在中国人的思维模式下,这种解释,才是真正的控制反转。

但,我们去了解IOC的实在内涵,完全不是这个意思。因此,建议大家忘记所谓的控制反转的翻译。个人觉得,可以理解为控制转移。就是绑匪失去了控制权。但是具体谁接受了控制权,有可能是小姐家人,有可能是官差,总归是第三方。

当然,后来出现的DI(依赖注入)的解释,就是从另外一个层面去描述这个问题。我觉得理解下,我讲的上边的例子就够了。

IOC,就是将两个关联依赖的对象,不再由其中一个对象,完成另外对象的实例创建,而是,把这种创建,交付给第三方实现。这两个对象间,仅仅是交互即可,无需关心实例创建问题。维护的是,对象与对象间的关系,更符合自然世界中的对象含义。

蜜蜂采花蜜,应该是蜜蜂 、花,两个对象,采蜜的过程,是蜜蜂依赖花,完成动作。那么,肯定是,花已经在,蜜蜂来踩。不能蜜蜂自己种一朵花,然后到了开花时节再来采。

Java是面向对象编程语言,要尽力的,以对象的语言,描述自然事物,这就是这个道理所在了。


IOC方式

正如我们在概念里聊得,已经比较透彻的聊了,IOC是什么,为什么产生这么一个方式。那么,具体的依赖注入,是如何实现的呢?

  • 属性注入
  • 构造器
  • setter方法注入
  • 接口实现注入 (不推荐)

注:针对Spring采用xml配置bean方式有同样的实现,只不过需要配置而已。

我们再此以SpringBoot为例说明,同时,我们以上边讲的蜜蜂采蜜这个来进行代码描述。

蜜蜂

@Component
public class Bee {
   /**
    * 性别
    */
   private String sex;
   /**
    * 年龄
    */
   private Integer age;
   /**
    * 采蜜
    */
   public void pickingHoney() {
       // 得到蜜
       flower.getHoney();
  }
    // 省略属性 setter getter
}

@Component
public class Flower {
   /**
    * 颜色
    */
   private String color;
    /**
    * 采蜜
    */
   public void getHoney() {
//
  }
    // 省略属性 setter getter
}

两个普通对象,通过添加注解@Component很容易就成为了bean,可以被Spring容易进行接管。

那么,蜜蜂,需要花的对象。如何得到,flower呢,我们了解到采用Spring容器提供的IOC技术,那么我们就来描述下

属性注入
@Component
public class Bee {
   /**
    * 性别
    */
   private String sex;
   /**
    * 年龄
    */
   private Integer age;
   @Autowired
   private Flower flower;
   /**
    * 采蜜
    */
   public void pickingHoney() {
       // 得到蜜
       flower.getHoney();
  }
    // 省略属性 setter getter
}

通过,注解@Autowired,即可进行属性注入。

构造器注入
@Component
public class Bee {
   /**
    * 性别
    */
   private String sex;
   /**
    * 年龄
    */
   private Integer age;
   private Flower flower;
   @Autowired
   public Bee(Flower flower) {
   this.flower = flower;
  }
   /**
    * 采蜜
    */
   public void pickingHoney() {
       // 得到蜜
       flower.getHoney();
  }
   // 省略属性 setter getter
}
接口实现注入

接口实现,是通过实现接口,重写方法,进行实现,不推荐,此处不多说。

setter方法注入
@Component
public class Bee {
   /**
    * 性别
    */
   private String sex;
   /**
    * 年龄
    */
   private Integer age;
   private Flower flower;
   @Autowired
   public void setFlower(Flower flower) {
   this.flower = flower;
  }
   /**
    * 采蜜
    */
   public void pickingHoney() {
       // 得到蜜
       flower.getHoney();
  }
   // 省略属性 setter getter
}

其中多种方式的优劣,可以查看公众号另外的文章 《SpringBoot依赖字段注入三种方式》。

聊完,依赖注入,必不可少的,牵扯到高频面试题,依赖注入产生循环依赖,如何解决?那么期待,后续解读文章。用最简单的话,让你明白记住,原理,面试不再发愁。

JVM类加载机制

聊完IOC,那么我们不妨聊下,Spring容器是如何把一个个的bean实例,进行加载的JVM中去的。

image.png

加载的过程就是,完成对于类class对象在内存中的生成、创建。那么这个如何加载,可以通过以下多种方式:

  • 编译的Class文件
  • ZIP包、Jar包等
  • 动态代理处理后的Class
  • 其他支持java语言文件生成,比如JSP文件

加载,完事后,就是一顿猛操作,进行在JVM中,处理,解析类对象是否符合规范等,解析类的内容。

再之后,初始化,开始执行类内代码。

除了,加载阶段,其他的都是在JVM控制下,处理。加载,是依靠类加载器。包括如下:

  • 根类加载器
  • 扩展类加载器
  • 应用类加载器
  • 自定义类加载器
根类加载器

根类加载器,是由C++开发,不在jvm中,因此,在jvm中读取,都会是null,属于所有类加载器的最根本的祖先级

扩展类加载器

Ext,用于读取Jdk中的Ext文件夹中的jar中的对象,比如rt.jar

应用类加载器

用于,加载应用的类对象

自定义类加载器

用于,自定义实现,实现类的加载

image.png

聊到这,就必须说一个经常出现的异常,类没有找到。

双亲委派机制

委派,就是委托处理;双亲委派,就是所有的加载最终都是由其双亲执行加载操作。

那么,当存在两个版本的jar,比如一个版本的功能是包含了最新的a操作,另一个版本没有。

那么,应用类加载器,虽然能发现最新的jar,但是双亲,扩展类加载器,发现不了,就会发生,类找不到异常。

当然,使用双亲委派是有好处的。

采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。

总结

今天呢,我们聊了两个面试题,希望大家好好掌握下。

目录
相关文章
|
2月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
1月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
156 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
21天前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
11天前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
49 9
|
9天前
|
存储 开发框架 Java
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
文章详细介绍了Spring、IOC、DI的概念和关系,解释了控制反转(IOC)和依赖注入(DI)的原理,并提供了IOC的代码示例,阐述了Spring框架作为IOC容器的应用。
14 0
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
|
18天前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
29 4
|
18天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
72 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
21天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
60 3
|
3天前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
15 0
|
1月前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit