IoC究竟是什么?——IoC的基础分析

IoC全称Inversion of Control,直译为控制反转。这是一种设计理念,并非技术。

在明白控制反转之前,应该知道"反转"反的是什么。

被反转的正转

我们从生活中的做饭场景开始。

在家做菜与餐馆吃饭

我们在做饭的时候有很多个步骤,需要准备原料,厨具等等。最后通过一定的顺序加入我们的原料,再进行翻炒等烹饪操作就能够得到一份菜了。

我们想吃一份菜不一定需要自己做,也可以去餐馆吃,只需要告诉餐馆我们要吃什么,餐馆就能自己做好给到我们手上吃

控制的正与反

在这个做饭的例子中,正转 就是我们自己准备原料,自己通过烹饪方法做菜,而控制反转 就是我们去的餐馆

这个时候我相信你还是不明白这俩有什么关系,为什么正转是自己做,而反转变成了餐馆的概念。没关系,我们继续深入。

什么是反转,反转在哪?

我们再回顾一遍,我们吃到菜是个什么流程。

  • 自己做饭:想好要做的菜------自己准备原料------自己烹饪------成品
  • 餐馆:想好要吃的菜------给餐馆说------餐馆烹饪------成品

我们自己设计一整套程序的时候,往往是有很多模块的,每个模块会相互协作使用,最终形成一个大的程序,我们需要自己一个一个将模块联系起来。这就是我们自己做菜的过程

而控制反转IoC就是将所有需要的模块通过一个容器(可以理解为一个控制终端)联系起来,我们不需要思考这个模块会不会使用其他的模块才能完成,全部都由容器帮我们完成联系。这就是我们去餐馆的过程,我们不用做菜,交给餐馆,而一个个原材料就是餐馆去准备的。

最终我们能看到反转的地方就在于,我们本来是靠自己去一个一个联系其模块来,但我们全都交给了容器,容器替我们完成了联系,我们反转了对自己的依赖,本来是依赖自己去联系的,现在变依赖容器,反转就在这。换句话说,控制反转应该叫控制反转

为什么要有IoC

这个时候你会说,这样不是省了很多事吗,省事不就是IoC的意义吗?

对了,但没完全对。换句话说,省事了,但没完全省。因为每个依赖还是要我们自己去配置的,只不过换了种方式(这个后面再说),IoC容器只是封装而已,但是这并不代表IoC没用,IoC最大的意义不在于它更方便,而是在于它能解耦

解耦在哪?

虽然容器只是帮我们完成了每个模块的依赖,但是我们前面说到,控制反转最大的意义就是我们只用把需要的功能给到容器,容器再去思考其他的,这样的话我们再写每个模块功能的时候就会更加独立,不用考虑依赖,每个模块变得更加独立那不就是解耦的初衷吗

实例

我们最后再来个实例看看效果

我们先创建一个接口

java 复制代码
public interface Shape { 
	void draw(); 
}

然后实现几个个接口

java 复制代码
//Rectangle.java
public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
java 复制代码
//Square.java
public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
java 复制代码
//Circle.java
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

然后根据传入信息的不同,生成不同的对象

java 复制代码
public class ShapeFactory {

   //use getShape method to get object of type shape 
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();

      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();

      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }

      return null;
   }
}

最后main方法调用,获取对象

java 复制代码
public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //get an object of Circle and call its draw method.
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //call draw method of Circle
      shape1.draw();

      //get an object of Rectangle and call its draw method.
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //call draw method of Rectangle
      shape2.draw();

      //get an object of Square and call its draw method.
      Shape shape3 = shapeFactory.getShape("SQUARE");

      //call draw method of circle
      shape3.draw();
   }
}

这就是工厂模式,工厂实现的方式原理是根据传入的某个参数获取一个对象,一旦我们新增一个shape类型,就修改ShapeFactory 类。这种方式不够灵活,并违背了软件设计的开闭原则。

开闭原则:一个软件实体, 如类, 模块, 函数等应该对扩展开放, 对修改封闭.

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对已有代码进行任何修改。

要想做到不修改的动态查看类的类型,反射就是一个不错的选择。

Java 反射(Reflection)是一个强大的特性,它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。

那么思路就有了,最后的修改就是这样:

java 复制代码
public class ShapeFactory {

    private ShapeFactory(){}
    public static Shape getInstance(String className){
        Shape shape = null;
        try {
            shape = (Shape) Class.forName(className).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return shape;
    }
}

而利用反射的代码就封装到了Class.forName里面

java 复制代码
@CallerSensitive
public static Class<?> forName(String className)
                throws ClassNotFoundException {
     Class<?> caller = Reflection.getCallerClass();
     return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

IOC底层原理主要用到了3种技术 :工厂模式、反射、XML解析

XML文件的配置这里我们不多说,下一章我们具体来说如何做,这里就明白我们的依赖管理都是类似于maven中的pom.xml一样管理的就行。

工厂模式、反射、XML解析的结合完成了IoC的所有技术概括,形成了巧妙的化学反应,我们后面spring都是基于整个概念在前行。

这可能是最好的Spring教程!

感谢您看到这里 这可能是最好的Spring教程系列 更多的文章可以到这查看这可能是最好的Spring教程!即便无基础也能看懂的入门Spring,仍在持续更新。,我还在荔枝更新出最详细的Spring教程

相关推荐
Tao____12 小时前
基于Ruoyi开发的IOT物联网平台
java·网络·物联网·mqtt·网络协议
花哥码天下12 小时前
apifox登录后设置token到环境变量
java·后端
浩瀚地学13 小时前
【Java】常用API(二)
java·开发语言·经验分享·笔记·学习
廋到被风吹走13 小时前
【Spring】Spring MVC核心原理与RESTful最佳实践详解
spring·mvc·restful
hashiqimiya13 小时前
springboot事务触发滚动与不滚蛋
java·spring boot·后端
因我你好久不见13 小时前
Windows部署springboot jar支持开机自启动
windows·spring boot·jar
PPPHUANG14 小时前
一次 CompletableFuture 误用,如何耗尽 IO 线程池并拖垮整个系统
java·后端·代码规范
恩创软件开发14 小时前
创业日常2026-1-8
java·经验分享·微信小程序·小程序