Spring是什么?IoC是什么?DI又是什么?

╰+哭是因爲堅強的太久メ 2024-03-23 13:51 282阅读 0赞

Spring是什么?

  Spring指的是Spring Framework(Spring框架)是包含了众多工具方法的IoC容器。

1.什么是容器?

  Spring是包含了众多工具方法的IoC容器。那么这里的容器是什么意思?很好理解,容器就是要能装东西、取东西,就好比如水杯、背包、还有数据结构中的Map、List等。那么Spring也是可以装东西、取东西,不过这里的这个“东西”就是java中的对象。(后文介绍)

  没错,Spring就是装对象的容器。(至于怎么存取对象,这里先不作讨论,本篇先注重其概念,详细的后面会更新。)

2.什么是IoC?

  IoC容器中的IoC是什么呢?IoC的全称是Inversion of Control,意思是“控制反转”,“控制反转”又是什么?我们通过下面的案例来慢慢体会“控制反转”是什么?

2.1 传统编程方式

  案例:制造自行车。

format_png

  要想造出一辆自行车必须要依赖轮子才能跑,轮子需要链条来转动,而链条需要脚踏板来牵引。

  1. //自行车
  2. public class Back {
  3. public void init(){
  4. //依赖轮胎
  5. Wheel weel = new Wheel();
  6. weel.init();
  7. }
  8. }
  9. //轮胎
  10. class Wheel{
  11. public void init(){
  12. //依赖链条
  13. Chain chain = new Chain();
  14. chain.init();
  15. }
  16. }
  17. //链条
  18. class Chain{
  19. public void init(){
  20. //依赖脚踏板
  21. Pedal pedal = new Pedal();
  22. pedal.init();
  23. }
  24. }
  25. //脚踏板
  26. class Pedal{
  27. private String shape = "正方形";
  28. public void init(){
  29. System.out.println("脚踏板的形状:" + shape);
  30. }
  31. }
  32. 复制代码
  33. public class Main{
  34. public static void main(String[] args) {
  35. Back back = new Back();
  36. back.init();
  37. }
  38. }
  39. 输出:脚踏板的形状:正方形
  40. 复制代码

  那如果现在我有新的需求了呢?比如我想要一个三角形的脚踏板,上面的代码该如何修改呢?其实可以在Pedal类里面加个构造方法:

  1. //脚踏板
  2. class Pedal{
  3. private String shape;
  4. //方便修改类型
  5. public Pedal(String shape){
  6. this.shape = shape;
  7. }
  8. public void init(){
  9. System.out.println("脚踏板的形状:" + shape);
  10. }
  11. }
  12. 复制代码

  我们虽然加了一个构造方法,但是这构造方法里的shape变量谁传进来呢?是上面的Chain传进来的,但是Chain里面没有shape呀,那么也是需要上一级的类传进来,最后的代码就是:

  1. //自行车
  2. public class Back {
  3. private Wheel wheel;
  4. //传进来什么就new什么
  5. public Back(String shape){
  6. wheel = new Wheel(shape);
  7. }
  8. public void init(){
  9. //依赖轮胎
  10. weel.init();
  11. }
  12. }
  13. //轮胎
  14. class Wheel{
  15. private Chain chain;
  16. //传进来什么就new什么
  17. public Wheel(String shape){
  18. chain = new Chain(shape);
  19. }
  20. public void init(){
  21. chain.init();
  22. }
  23. }
  24. //链条
  25. class Chain{
  26. private Pedal pedal;
  27. //传进来什么就new什么
  28. public Chain(String shape){
  29. pedal = new Pedal(shape);
  30. }
  31. public void init(){
  32. //依赖脚踏板
  33. pedal.init();
  34. }
  35. }
  36. //脚踏板
  37. class Pedal{
  38. private String shape;
  39. public Pedal(String shape){
  40. this.shape = shape;
  41. }
  42. public void init(){
  43. System.out.println("脚踏板的形状:" + shape);
  44. }
  45. }
  46. 复制代码
  47. //测试类
  48. class Main{
  49. public static void main(String[] args) {
  50. //传入我们得需求:“三角形”
  51. Back back = new Back("三角形");
  52. back.init();
  53. }
  54. }
  55. 结果:脚踏板的形状:三角形
  56. 复制代码

  从上面的代码可以看出,当最底层的代码改动后,整个调用链上的所有的代码都是要修改的,耦合性很高。

  是什么原因导致的上面的问题呢?问题出现在每个类⾃⼰创建了下级类,这就会出现当下级类发⽣改变时,⾃⼰也要跟着修改。

2.2 控制反转的方式

  问题已经找到了,那么解决方法就出来了:我们将原来自己创建下级类的方式改为传递的方式:

  1. //自行车
  2. public class Back {
  3. private Wheel wheel;
  4. //需要外面传入一个轮胎,而不是我自己造了
  5. public Back(Wheel wheel){
  6. this.wheel = wheel;
  7. }
  8. public void init(){
  9. //依赖轮胎
  10. wheel.init();
  11. }
  12. }
  13. //轮胎
  14. class Wheel{
  15. private Chain chain;
  16. //需要外面传入一个链条,而不是我自己造了
  17. public Wheel(Chain chain){
  18. this.chain = chain;
  19. }
  20. public void init(){
  21. chain.init();
  22. }
  23. }
  24. //链条
  25. class Chain{
  26. private Pedal pedal;
  27. //需要外面传入一个脚踏板,而不是我自己造了
  28. public Chain(Pedal pedal){
  29. this.pedal = pedal;
  30. }
  31. public void init(){
  32. //依赖脚踏板
  33. pedal.init();
  34. }
  35. }
  36. //脚踏板
  37. class Pedal{
  38. private String shape;
  39. public Pedal(String shape){
  40. this.shape = shape;
  41. }
  42. public void init(){
  43. System.out.println("脚踏板的边长:" + shape);
  44. }
  45. }
  46. //测试类
  47. class Main{
  48. public static void main(String[] args) {
  49. Pedal pedal = new Pedal("长方形");//外面造一个脚踏板
  50. Chain chain = new Chain(pedal);//传入,造个链条
  51. Wheel wheel = new Wheel(chain);//传入,造个轮胎
  52. Back back = new Back(wheel);//传入,造自行车
  53. back.init();
  54. }
  55. }
  56. 结果:脚踏板的边长:长方形
  57. 复制代码

  上面的方式,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的, 这样就解耦了。

format_png 1

2.3 再来理解IoC

  我们用上面的案例来理解,我们来对比两种方式的类的创建顺序:

format_png 2

  第一种方式是先创建Back类然后依次往下创建,前一个类依赖于后一个类,后一个类修改后,前一个类也必须修改;上级类控制下级类,因为在上级类中是通过new的方式创建下级类的。

  第二种方式是从后往前的创建,但是这里的是下级对象注⼊到当前对象中,在当前类中我不操心怎么new的对象,我只管用就行了,上级类不再控制下级类了,当前类都是不受影响的,这就是典型的控制反转(IoC) 的实现思想。

2.4 什么是 Spring IoC 容器?

  上文提到:Spring 是包含了多个⼯具⽅法的IoC 容器,那怎么理解 Spring 是 IoC容器呢?

  既然是容器,那么Spring将对象存⼊到容器、并且能从容器中取出对象。怎么理解这句话?就是将对象存储在容器中,以后需要的时候直接取就⾏了,⽤完再把它放回到仓库,而不用自己去new一个对象了,不用管new的细节了。

  这与IoC有什么联系呢?在这之前我们先得先了解 DI(Dependency Injection)是什么?

2.4 什么是 DI ?

  DI的英文是(Dependency Injection),意思是依赖注入。提到“注入”有没有想到什么?我们上文的案例中第二种方式提到过,怎么造一个自行车?就是下级类通过注入的方式,将下级类传入到上级类。这中间有一个要注意的点,那就是中间没有new的环节!我是直接传进来的,以Main类之外的视角来看,我是不需要操心怎么去new的,我只负责接受就行了。

  那么这里的DI就是这个作用,DI就相当于把容器中的类取出来让我们用的这个过程,我们不需要操心怎么去new的,在Spring中是通过注解的方式来实现这个过程。下面是简单的示意图(详细的介绍待更新)。

  1. //轮胎
  2. @Controller
  3. class Wheel{
  4. @Autowired//这里就是将容器中的 Chain 对象注入进来(直接复值),不用我们自己 new 一个。
  5. private Chain chain;
  6. public void init(){
  7. chain.init();
  8. }
  9. }
  10. //链条
  11. @Controller
  12. class Chain{
  13. @Autowired//这里就是将容器中的 Pedal 对象注入进来(直接复值),不用我们自己 new 一个。
  14. private Pedal pedal;
  15. public void init(){
  16. pedal.init();
  17. }
  18. }
  19. 复制代码

  这就是DI(Dependency Injection)依赖注入的意思,回到上面的问题:这与IoC有什么联系呢?Spring通过DI(依赖注入)的方式可以实现控制反转来解耦合,有了控制反转不就是IoC了吗?, Spring注解等方式来实现依赖注入从而进行控制反转,并且它是一个装对象的容器。所以Spring是一个IoC容器。

ID(依赖注入)IoC(控制反转)的一种实现方式,IoC 是“⽬标”也是⼀种思想或者是设计模式,⽽DI就属于具体的实现。

  下面我们看看CatGPT是如何“理解”IoC以及DI的:

format_png 3

format_png 4

format_png 5

发表评论

表情:
评论列表 (有 0 条评论,282人围观)

还没有评论,来说两句吧...

相关阅读

    相关 什么 Spring IOC 容器?

    Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通

    相关 什么DI

    > Spring致力于简化java企业级开发,促进代码松耦合,成功的关键在于依赖注入和AOP > Spring通过应用上下文(Application Context)装载b