前言

上一篇文章已经学习了【IoC的主要实现策略】有2种:

1、依赖查找

2、依赖注入

这里稍加详细的介绍一下依赖查找

1.依赖查找的方式

依赖查找的方式可以以多种维度来划分:

1.按名称/类型/注解查找

2.按单一类型/集合类型/层次性依赖查找

3.延迟查找、实时查找

1.1维度一

1.1.1根据 Bean 名称查找

实时
    private static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找:" + user);
}
延迟
    private static void lookupInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("延迟查找:" + user);
}
这里省略了一个名为user的bean
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>

1.1.2根据 Bean 类型查找

    private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("实时查找:" + user);
}

1.1.3根据 Java注解查找

    private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("查找标注 @Super 所有的 User 集合对象:" + users);
}
}

1.2维度二

1.2.1单一类型查找

单一类型的查找是基于BeanFactory这个接口来实现的。

  • 根据Bean名称查找

    • getBean(String)
  • 根据Bean类型查找
    • Bean实时查找

      • getBean(Class)
    • Bean延迟查找 (Spring5.1)
      • getBeanProvider(Class)
      • getBeanProvider(ResolvableType)
  • 根据Bean名称+类型查找
    • getBean(String, Class)

1.2.2集合类型查找

集合类型的查找是基于ListableBeanFactory这个接口来实现的。

  • 根据Bean类型查找

    • 获取同类型Bean名称列表

      • getBeanNamesForType(Class)
      • getBeanNamesForType(ResolvableType) [Spring4.2]
    • 获取同类型Bean实例列表
      • getBeansOfType(Class)以及它的重载方法
  • 根据注解类型查找
    • Spring3.0获取标注类型Bean名称列表

      • getBeanNamesForAnnotation(Class<? extends Annotation>)
    • Spring3.0获取标注类型Bean实例列表
      • getBeansWithAnnotation(Class<? extends Annotation>)
    • Spring3.0获取指定名称 + 标注类型Bean实例
      • findAnnotationOnBean(String, Class<? extends Annotation>)

1.2.3层次性查找

层次性类型的查找是基于HierarchicalBeanFactory这个接口来实现的。

这里的层次性查找是有一点类似于类加载的双亲委派,但是它的实现是需要依赖于下面接口的方法:

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
/**
* Set the parent of this bean factory.
* <p>Note that the parent cannot be changed: It should only be set outside
* a constructor if it isn't available at the time of factory instantiation.
* @param parentBeanFactory the parent BeanFactory
* @throws IllegalStateException if this factory is already associated with
* a parent BeanFactory
* @see #getParentBeanFactory()
*/
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;

实现的基本逻辑就是:

1.获取到子BeanFactory

2.创建一个ParentBeanFactory

3.设置父子关系

4.获取bean的时候,先判断其ParentBeanFactory是否存在,不存在,则判断子BeanFactory是否存在。使用递归。

这里我不是很清楚层次性依赖查找有什么用处,目前的项目业务中一般只会有默认的Spring创建的BeanFactory。

1.3维度三

1.3.1延迟查找

延迟查找可以用过2个接口实现:

1、ObjectFactory

2、ObjectProvider

其中ObjectProvider继承了ObjectFactory:

public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {

这里的延迟查找:

基本原理就是

1.通过AbstractApplicationContext接口的方法:getBeanProvider(Class<T> requiredType)获取到一个ObjectFactory或ObjectProvider的实例

2.当真正需要使用指定类型【上一步的requiredType】的实例的时候,调用ObjectFactory实例【上一步的返回值】的T getObject(),在第二步才是真正的执行依赖查找。

示例

    private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class); //第一步
System.out.println(objectProvider.getObject()); //第二步,这一步跟进源码,可以知道这一步是怎么实际查找的。
//DependencyObjectProvider.java
}

非延迟初始化Bean也能实现延迟查找:

也就是说 即时初始化的bean也能实现延迟查找。

实际的ObjectProvider实现类一般是在DefaultListableBeanFactory.java中的内部类DependencyObjectProvider.java:

1.3.2实时查找

除了延迟查找,基本都是实时查找,没什么好说的。

2.依赖查找的安全性

3.Spring内建依赖

Spring默认容器启动的时候,有一些内置的依赖,这些依赖是帮助spring实现某些基础功能所需的。算是Spring给自身的扩展和增强。





4.依赖查找的经典异常

【Spring】IoC容器 - 依赖查找的更多相关文章

  1. Spring IOC容器装配Bean_基于注解配置方式

    bean的实例化 1.导入jar包(必不可少的) 2.实例化bean applicationContext.xml(xml的写法) <bean id="userDao" cl ...

  2. 【Spring】IoC容器 - 依赖来源

    前言 上一篇文章已经学习了[依赖注入]相关的知识,这里详细的介绍一下[依赖来源]. 依赖来源 我们把依赖来源分为依赖查找的来源和依赖注入的来源分别讨论. 依赖查找的来源 1. Spring BeanD ...

  3. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

  4. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  5. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  6. 纯注解快速使用spring IOC容器

    使用spring的ioc容器实现对bean的管理与基本的依赖注入是再经典的应用了.基础使用不在详述. 这里主要介绍下使用注解实现零配置的spring容器.我相信你也会更喜欢使用这种方式.Spring ...

  7. Spring IOC容器基本原理

    2.2.1 IOC容器的概念IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IOC容器 ...

  8. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  9. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

随机推荐

  1. 手动编译部署LNMP环境(CentOS7.5+Nginx-1.18.0+MySQL-5.7.30+PHP-7.4.14)

    在平时运维工作中,经常需要用到LNMP应用框架.LNMP环境是指在Linux系统下,由Nginx + MySQL + PHP组成的网站服务器架构. 可参考前面的文章: 如何在CentOS 7上搭建LA ...

  2. GIT:创建、查看分支命令(git branch -vv)

    在开发过程中一般会用到Git进行版本管理,创建查看分支并与远程仓库交互是非常常见的操作. branch分支 是指在开发主线中分离出来的,做进一步开发而不影响到原来的主线. Git存储的不是一系列的更改 ...

  3. weblogic从ssrf到redis获取shell

    一.环境搭建和知识储备 1.1.影响版本 漏洞编号:CVE-2014-4210 weblogic 10.0.2.0 weblogic 10.3.6.0 1.2.Docker搭建环境 1.进入vulhu ...

  4. 编译执行 VS 解释执行

    一般编译程序从对源程序执行途径的角度不同,可分为解释执行和编译执行. 所谓解释执行是借助于解释程序完成,即按源程序语句运行时的动态结构,直接逐句地边分析边翻译并执行.像自然语言翻译中的口译,随时进行翻 ...

  5. 什么是maven与maven的使用过程(例如在idea创建maven工程(重点讲讲idea创建使用maven管理的web工程,并且部署到tomcat上))

    什么是maven与maven的使用过程(例如在idea创建maven工程) (重点讲讲idea创建使用maven管理的web工程项目,并且部署到tomcat服务器上) 一.什么是maven? 1, M ...

  6. linux重启mysql

    一. 启动1.使用 service 启动:service mysql start2.使用 mysqld 脚本启动:/etc/inint.d/mysql start3.使用 safe_mysqld 启动 ...

  7. 记一次k8s pod频繁重启的优化之旅

    关键词:k8s.jvm.高可用 1.背景 最近有运维反馈某个微服务频繁重启,客户映像特别不好,需要我们尽快看一下. 听他说完我立马到监控平台去看这个服务的运行情况,确实重启了很多次.对于技术人员来说, ...

  8. Python3入门系列之-----json与字典转换

    json JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写 JSON 函数 使用 JSON 函数需要导入 json 库:import js ...

  9. vue项目中的element-ui地区级联选择器加详细地址push到对象中不显示的问题

    想要实现级联选择器el-cascader和输入框el-input共同组成的详细地址,添加数据时弹出el-drawer嵌套el-form弹窗,然后在el-form添加数据提交后push到el-table ...

  10. SSA

    wikipedia上关于SSA的定义如下: In compiler design, static single assignment form (often abbreviated as SSA fo ...