Spring 源码阅读 05:忽略感知接口对应成员变量的自动装配

简介: 在 Spring 中,Aware 接口也被叫做感知接口,当一个 Bean 实现了感知接口的时候,Spring 创建 Bean 的时候,就会通过调用感知接口的方法注入相应的数据。

基于 Spring Framework v5.2.6.RELEASE

接前文:Spring 源码阅读:BeanFactory 初始化

这篇内容是补充之前在 BeanFactory 初始化 一文中留的一个坑,前文提到了 BeanFactory 的实例化是在 AbstractRefreshableApplicationContext#createBeanFactory 方法中完成的,这里会通过构造方法创建一个 DefaultListableBeanFactory 类型的 BeanFactory,如下:

protectedDefaultListableBeanFactorycreateBeanFactory() {
returnnewDefaultListableBeanFactory(getInternalParentBeanFactory());
}

这里的 getInternalParentBeanFactory() 获取的是当前容器的父容器对应的 BeanFactory,如果读过之前的相关文章就会知道,在创建当前容器的时候,父容器是空的。

DefaultListableBeanFactory 的构造方法源码如下:

publicDefaultListableBeanFactory(@NullableBeanFactoryparentBeanFactory) {
super(parentBeanFactory);
}

这里直接调用了父类 AbstractAutowireCapableBeanFactory 的构造方法:

publicAbstractAutowireCapableBeanFactory(@NullableBeanFactoryparentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}

代码中有两个步骤,这篇文章主要分析一下这两部分的源码。

顺便把 DefaultListableBeanFactory 的类继承关系放在这里供参考:

image.png

无参构造方法

第一个步骤,是调用了本身的无参构造方法,源码如下:

publicAbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}

这里首先调用了父类的构造方法,不过父类的构造方法是一个空方法,因此我们重点关注下面的逻辑,也就是 3 次 ignoreDependencyInterface 方法的调用。我们查看 ignoreDependencyInterface 的源码:

publicvoidignoreDependencyInterface(Class<?>ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}

逻辑很简单,就是当前的 BeanFactory 有一个集合类型的成员变量 ignoredDependencyInterfaces,三次调用这个方法就是把 BeanNameAwareBeanFactoryAwareBeanClassLoaderAware 这三个接口放在了这个集合里面。

接下来,我们的任务就是分析出将接口放在 ignoredDependencyInterfaces 的作用是什么。

感知接口

先看被添加到 ignoredDependencyInterfaces 中的三个接口。

image.png

这三个接口的名字都是 XXXAware,都继承自 Aware 接口,并且都只包含一个与接口名对应的 setXXX 方法。

相信使用 Spring 框架的小伙伴对 Aware 接口都非常了解,这里在简单总结一下。

在 Spring 中,Aware 接口也被叫做感知接口,当一个 Bean 实现了感知接口的时候,Spring 创建 Bean 的时候,就会通过调用感知接口的方法注入相应的数据。

举个例子,我需要在一个 Bean 中使用当前 Bean 在 Spring 容器中的名称,也就是 beanName,那么,我在开发这个类的时候,就可以实现 BeanNameAware 接口,并实现其 setBeanName(String name) 方法。当 Spring 实例化这个类的时候,发现其实现了 BeanNameAware 接口,然后,就会通过调用 setBeanName 方法,将 Bean 的名称传递进来。

更详细的流程,等到之后的代码分析中再探讨。

忽略指定接口的自动感知功能

了解了感知接口及其作用,我们再来看 ignoredDependencyInterfaces 的作用。通过在 IDE 中查找 ignoredDependencyInterfaces 的用法,发现除了调用 addaddAll 方法向集合中添加接口意外,只有 isExcludedFromDependencyCheck 方法地方用到了它:

image.png

我们找到这个方法的源码:

/*** Determine whether the given bean property is excluded from dependency checks.* <p>This implementation excludes properties defined by CGLIB and* properties whose type matches an ignored dependency type or which* are defined by an ignored dependency interface.* @param pd the PropertyDescriptor of the bean property* @return whether the bean property is excluded* @see #ignoreDependencyType(Class)* @see #ignoreDependencyInterface(Class)*/protectedbooleanisExcludedFromDependencyCheck(PropertyDescriptorpd) {
return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
}

根据方法的名称和注释判断,这个方法的作用是判断一个 Bean 的成员变量是否要从依赖检查中排除掉。我们只看跟 ignoredDependencyInterfaces 有关的最后一个判断条件:

AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)

被调用的 AutowireUtils.isSetterDefinedInInterface 方法的源码如下:

/*** Return whether the setter method of the given bean property is defined* in any of the given interfaces.* @param pd the PropertyDescriptor of the bean property* @param interfaces the Set of interfaces (Class objects)* @return whether the setter method is defined by an interface*/publicstaticbooleanisSetterDefinedInInterface(PropertyDescriptorpd, Set<Class<?>>interfaces) {
Methodsetter=pd.getWriteMethod();
if (setter!=null) {
Class<?>targetClass=setter.getDeclaringClass();
for (Class<?>ifc : interfaces) {
if (ifc.isAssignableFrom(targetClass) &&ClassUtils.hasMethod(ifc, setter)) {
returntrue;
         }
      }
   }
returnfalse;
}

方法中传入的两个参数,一个表示要进行判断的属性,另一个则是 ignoredDependencyInterfaces。首先,获取给定属性的 setter 方法及其对应的类,遍历 ignoredDependencyInterfaces 中的每一个接口,并判断这个类是否实现了当前遍历到的接口,以及接口中是否包含同样的 setter 方法。如果以上两个判断的结果都是 true,整个方法的返回值也就是 true,就代表这个属性需要通过感知接口的方法来进行诸如,Spring 就不会在创建这个 Bean 的时候通过自动装配来给这个属性注入值。

setParentBeanFactory

第二个步骤是通过调用 parentBeanFactory 将构造方法参数中的 parentBeanFactory 赋值给对应的成员变量:

@OverridepublicvoidsetParentBeanFactory(@NullableBeanFactoryparentBeanFactory) {
if (this.parentBeanFactory!=null&&this.parentBeanFactory!=parentBeanFactory) {
thrownewIllegalStateException("Already associated with parent BeanFactory: "+this.parentBeanFactory);
   }
if (this==parentBeanFactory) {
thrownewIllegalStateException("Cannot set parent bean factory to self");
   }
this.parentBeanFactory=parentBeanFactory;
}

这一步骤比较简单。


这部分代码就分析到这里,关于 Spring 实例化 Bean 的具体步骤,会在之后的文章中进行分析,敬请关注。

目录
相关文章
|
6天前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
39 0
|
6天前
|
监控 数据可视化 安全
一套成熟的Spring Cloud智慧工地平台源码,自主版权,开箱即用
这是一套基于Spring Cloud的智慧工地管理平台源码,具备自主版权,易于使用。平台运用现代技术如物联网、大数据等改进工地管理,服务包括建设各方,提供人员、车辆、视频监控等七大维度的管理。特色在于可视化管理、智能报警、移动办公和分布计算存储。功能涵盖劳务实名制管理、智能考勤、视频监控AI识别、危大工程监控、环境监测、材料管理和进度管理等,实现工地安全、高效的智慧化管理。
|
6天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
25 6
|
6天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
32 3
|
6天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
17 1
|
6天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
108 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
6天前
|
Java Spring
spring boot访问接口报500
spring boot访问接口报500
15 2
|
6天前
|
设计模式 安全 Java
【初学者慎入】Spring源码中的16种设计模式实现
以上是威哥给大家整理了16种常见的设计模式在 Spring 源码中的运用,学习 Spring 源码成为了 Java 程序员的标配,你还知道Spring 中哪些源码中运用了设计模式,欢迎留言与威哥交流。
|
6天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
6天前
|
Java 数据库连接 数据库
spring+mybatis_编写一个简单的增删改查接口
spring+mybatis_编写一个简单的增删改查接口
17 2