Spring中的IOC深度解读

 更新时间:2023年09月15日 08:49:03   作者:猎户星座。  
这篇文章主要介绍了Spring中的IOC深度解读,spring容器会创建和组装好清单中的对象,然后将这些对象存放在spring容器中,当程序中需要使用的时候,可以到容器中查找获取,然后直接使用,需要的朋友可以参考下

spring容器

spring容器的概念,容器这个名字起的相当好,容器可以放很多东西,我们的程序启动的时候会创建spring容器,会给spring容器一个清单,清单中列出了需要创建的对象以及对象依赖关系,spring容器会创建和组装好清单中的对象,然后将这些对象存放在spring容器中,当程序中需要使用的时候,可以到容器中查找获取,然后直接使用。

IOC:控制反转

使用者之前使用B对象的时候都需要自己去创建和组装,而现在这些创建和组装都交给spring容器去给完成了,使用者只需要去spring容器中查找需要使用的对象就可以了;这个过程中B对象的创建和组装过程被反转了,之前是使用者自己主动去控制的,现在交给spring容器去创建和组装了,对象的构建过程被反转了,所以叫做控制反转;IOC是是面相对象编程中的一种设计原则,主要是为了降低系统代码的耦合度,让系统利于维护和扩展。

DI:依赖注入

依赖注入是spring容器中创建对象时给其设置依赖对象的方式,比如给spring一个清单,清单中列出了需要创建B对象以及其他的一些对象(可能包含了B类型中需要依赖对象),此时spring在创建B对象的时候,会看B对象需要依赖于哪些对象,然后去查找一下清单中有没有包含这些被依赖的对象,如果有就去将其创建好,然后将其传递给B对象;可能B需要依赖于很多对象,B创建之前完全不需要知道其他对象是否存在或者其他对象在哪里以及被他们是如何创建,而spring容器会将B依赖对象主动创建好并将其注入到B中去,比如spring容器创建B的时候,发现B需要依赖于A,那么spring容器在清单中找到A的定义并将其创建好之后,注入到B对象中。

spring中依赖注入主要分为手动注入和自动注入:

手动注入需要由程序员自己配置、描述好依赖关系,来实现自动注入(但是实际开发中手动装配的场景比较少,比如在缺少源码的情况下可能会使用这种手动装配情况)。

自动注入采用约定大于配置的方式来实现的,程序和spring容器之间约定好,遵守某一种都认同的规则,来实现自动注入。

DI:依赖注入的实现方式

分别是基于构造方法的依赖注入和基于setter(setXxxx(…))的依赖注入。

不管是手动装配还是自动装配都是基于这两种方式或者变体方式来的;但是这里一定要回答到主要和变体两个名词,因为有的注入方式就不是这两种,而是这两种其中一种的变体方式;比如在一个类的属性上面加@Autowired,这种方式注入属性的方式就是利用了java的反射知识,field.set(value,targetObject);关于这个我在后面的文章中对spring源码解析的时候会说明@Autowired的原理;所以@Autowired这种注入的方式是setter注入方式的一种变体

DI:依赖注入的自动装配模型

依赖注入是一个过程,主要通过setter或构造方法以及一些变体的方式完成把对象依赖、或者填充上的这个过程叫做依赖注入,不管手动装配还是自动装配都有这个过程;

手动装配通过ref标签来指定依赖关系,而自动装配没有显示的指定依赖关系,所以需要通过一些规则,来从容器中查找到符合条件的bean进行自动装配的工作,而自动装配模型就是完成自动装配依赖的手段体现。

每一种模型都使用了不同的技术去查找和填充bean;而从spring官网上面可以看到spring只提出了4中自动装配模型(严格意义上是三种、因为第一种是no,表示不使用自动装配、使用),这四个模型分别用一个整形来表示,存在spring的beanDefinition当中,任何一个类默认是no这个装配模型

我们可以在AutowireCapableBeanFactory类中看下这几种自动装配模型对应的整形分别是多少

public interface AutowireCapableBeanFactory extends BeanFactory {
	int AUTOWIRE_NO = 0;
	int AUTOWIRE_BY_NAME = 1;
	int AUTOWIRE_BY_TYPE = 2;
	int AUTOWIRE_CONSTRUCTOR = 3;
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;
}

@Autowired就是根据byType来进行自动装配

我们先抛出@Autowired的查找逻辑的结论:

首先spring根据类型去容器中找,找到了直接注入。如果根据类型找到了多个,那么spring不会立马异常,而是根据名字再去找,如果根据名字找到一个合理的则注入这个合理的。

如果没有找到,再根据名字去找,找到了则注入,没有找到则报异常。

我们再来用代码来验证下

定义一个空接口I,XY类分别实现I接口,Z类中注入I

public interface I {
}
package com.yj.service.impl;
import org.springframework.stereotype.Component;
import com.yj.service.I;
@Component("ix")
public class X implements I{
}
package com.yj.service.impl;
import org.springframework.stereotype.Component;
import com.yj.service.I;
@Component("iy")
public class Y implements I{
}
@Component
public class Z {
	@Autowired
	private I ix;
	public I getIx() {
		return ix;
	}
	public void setIx(I ix) {
		this.ix = ix;
	}
}

扫描配置类

package com.yj.conf;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.yj")
public class AppConfig {
}

MyBeanFactoryProcessor

package com.yj.conf;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
        AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)beanFactory.getBeanDefinition("z");
        //beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        System.out.println("beanDefinition.getAutowireMode():"+beanDefinition.getAutowireMode());
    }
}

首先,我们可以观察到被@Autowired注解的z类的getAutowireMode值为0,不是2。而且我们如果手动将z类的AutowireMode设置为ByType,只是根据类型来查找的话,会查出XY两个bean,程序会报错的。

但是采用@Autowired默认的注入方式,是不会报错的,也就是说@Autowired的查找逻辑并不能简单的认为等价于ByType,@Autowired首先根据类型然后再根据名字去查找,完成bean注入的过程。

到此这篇关于Spring中的IOC深度解读的文章就介绍到这了,更多相关IOC深度解读内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot初始化接口CommandLineRunner示例详解

    SpringBoot初始化接口CommandLineRunner示例详解

    这篇文章主要介绍了SpringBoot初始化接口CommandLineRunner,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Java中SynchronousQueue的底层实现原理剖析

    Java中SynchronousQueue的底层实现原理剖析

    BlockingQueue的实现类中,有一种阻塞队列比较特殊,就是SynchronousQueue(同步移交队列),队列长度为0。本文就来剖析一下SynchronousQueue的底层实现原理,感兴趣的可以了解一下
    2022-11-11
  • 基于Java实现音乐播放器的示例代码

    基于Java实现音乐播放器的示例代码

    这篇文章主要为大家详细介绍了如何利用Java编写一个简单的音乐播放器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-07-07
  • Java 栈和队列的交互实现

    Java 栈和队列的交互实现

    栈和队列都是常用的数据结构,本文就来介绍一下Java 栈和队列的交互实现,主要包括队列模拟实现栈及栈模拟实现队列,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • java基础理论Stream管道流Map操作示例

    java基础理论Stream管道流Map操作示例

    这篇文章主要未大家介绍了java基础理论Stream管道流Map操作方法示例解析,有需要的朋友可以借鉴参考下希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java国密加密SM2代码详细使用步骤

    Java国密加密SM2代码详细使用步骤

    SM2算法可以用较少的计算能力提供比RSA算法更高的安全强度,而所需的密钥长度却远比RSA算法低,下面这篇文章主要给大家介绍了关于Java国密加密SM2代码的相关资料,需要的朋友可以参考下
    2024-07-07
  • Java 输入多行字符串或者多个int数值的方法

    Java 输入多行字符串或者多个int数值的方法

    今天小编就为大家分享一篇Java 输入多行字符串或者多个int数值的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • 深入了解Java内部类的用法

    深入了解Java内部类的用法

    java类的五大成员:属性,方法,构造器(构造方法),代码块,内部类。本文就来和大家详细讲讲ava内部类的用法,需要的小伙伴可以参考一下
    2022-07-07
  • mac 安装java1.8的过程详解

    mac 安装java1.8的过程详解

    这篇文章主要介绍了mac 安装java1.8,包括下载过程及配置环境相关知识介绍,本文结合实例代码介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • 常用输入字节流InputStream介绍

    常用输入字节流InputStream介绍

    下面小编就为大家带来一篇常用输入字节流InputStream介绍。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08

最新评论