【框架源码篇 05】Spring源码篇-ApplicationContext

news2024/10/4 22:29:47

Spring源码篇-ApplicationContext

  前面通过手写IoC,DI、AOP和Bean的配置。到最后ApplicationContext的门面处理,对于Spring相关的核心概念应该会比较清楚了。接下来我们就看看在Spring源码中,对于的核心组件是如何实现的。

一、ApplicationContext

  ApplicationContext到底是什么?字面含义是应用的上下文。这块我们需要看看ApplicationContext的具体的结构。

image.png

  通过ApplicationContext实现的相关接口来分析,ApplicationContext接口在具备BeanFactory的功能的基础上还扩展了 应用事件发布,资源加载,环境参数国际化的能力。然后我们来看看ApplicationContext接口的实现类的情况。

image.png

  在ApplicationContext的实现类中有两个比较重要的分支 AbstractRefreshableApplicationContextGenericApplicationContext.

image.png

二、BeanFactory

  上面分析了 ApplicationContext接口的结构。然后我们来看看 BeanFactory在ApplicationContext中具体的实现是怎么样的

image.png

image.png

可以看到具体的实现是 DefaultListableBeanFactory .然后我们来看看他的体系结构

image.png

BeanFactory的继承体系

image.png

三、BeanDefinition

  然后我们来了解下ApplicationContext是如何来加载Bean定义的。具体代码我们需要分为XML配置文件和基于注解的两种方式来看。

1.基于XML方式

  我们先定义对应的application.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

	<bean id="beanE" class="com.study.spring.sample.config.BeanE" />

	<bean id="beanF" class="com.study.spring.sample.config.BeanF" ></bean>

	<context:annotation-config/>

	<context:component-scan base-package="com.study.spring.sample.config" ></context:component-scan>

</beans>

然后我们的测试类代码

public class XMLConfigMain {

	public static void main(String[] args) {
		ApplicationContext context = new GenericXmlApplicationContext(
				"classpath:com/study/spring/sample/config/application.xml");
		BeanF bf = context.getBean(BeanF.class);
		bf.do1();
	}
}

处理的过程 解析XML --> BeanDefinition --> BeanDefinitionRegistry --> BeanFactory

image.png

2.基于注解方式

  然后来看看基于注解方式的使用的情况。首先是我们的配置类

@Configuration
@ComponentScan("com.study.spring.sample.config")
public class JavaBasedMain {

	@Bean
	public BeanH getBeanH() {
		return new BeanH();
	}

	public static void main(String[] args) {
		ApplicationContext context = new AnnotationConfigApplicationContext(JavaBasedMain.class);

		BeanH bh = context.getBean(BeanH.class);
		bh.doH();
	}
}

然后是我们的测试类

public class AnnotationMain {

	public static void main(String[] args) {
		ApplicationContext context = new AnnotationConfigApplicationContext("com.study.spring.sample.config");

		BeanG bg = context.getBean(BeanG.class);
		bg.dog();
	}
}

注解使用有两种方法:

  1. 配置扫描路径
  2. 配置@Configuration的注解类

2.1 this构造方法

  在this的构造方法中会完成相关的配置处理。

	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

首先是AnnotatedBeanDefinitionReader(this)方法。会完成核心的ConfigurationClassPostProcessor的注入。ConfigurationClassPostProcessor 会完成@Configuration相关的注解的解析

image.png

this.scanner其实就是创建了一个对应的扫描器

image.png

2.2 扫描实现

  扫描就需要进入到scan方法中。

image.png

image.png

image.png

完成相关的注册

image.png

2.3 @Configuration

  @Configuration的解析其实是在refresh方法中来实现的。

image.png

3.小结

  通过上面的分析其实我们已经对Bean定义的扫描,解析和注册过程有了一定的了解。归纳为:

  1. reader解析XML,完成xml方法配置的bean定义
  2. scanner扫描指定包下的类,找出带有@Component注解的类,注册成Bean定义
  3. 通过ConfigurationClassPostProcessor对带有@Configuration注解的类进行处理,解析它上面的注解,以及类中带有@Bean 注解,加入这些的Bean的定义。

4.BeanDefinition

  ;然后我们来看看BeanDefinition的继承结构

image.png

  继承属性访问器和元数据接口,增加了Bean定义操作,实现了数据和操作解耦。属性访问器和元数据接口接着往下看。

4.1 BeanMetadataElement

  BeanMetadataElement提供了获取数据源的方式,也就是可以指导Bean是来自哪个类。

public interface BeanMetadataElement {

	/**
	 * Return the configuration source {@code Object} for this metadata element
	 * (may be {@code null}).
	 */
	@Nullable
	default Object getSource() {
		return null;
	}

}

4.2 BeanMetadataAttribute元数据属性

  实现了元数据接口,增加了属性的名字和值。。


public class BeanMetadataAttribute implements BeanMetadataElement {

	private final String name;

	@Nullable
	private final Object value;

	@Nullable
	private Object source;

}

4.3 AttributeAccessor属性访问器

  AttributeAccessor用来给Bean定义了增删改查属性的功能

public interface AttributeAccessor {

	/**
	 * Set the attribute defined by {@code name} to the supplied {@code value}.
	 * If {@code value} is {@code null}, the attribute is {@link #removeAttribute removed}.
	 * <p>In general, users should take care to prevent overlaps with other
	 * metadata attributes by using fully-qualified names, perhaps using
	 * class or package names as prefix.
	 * @param name the unique attribute key
	 * @param value the attribute value to be attached
	 */
	void setAttribute(String name, @Nullable Object value);

	/**
	 * Get the value of the attribute identified by {@code name}.
	 * Return {@code null} if the attribute doesn't exist.
	 * @param name the unique attribute key
	 * @return the current value of the attribute, if any
	 */
	@Nullable
	Object getAttribute(String name);

	/**
	 * Remove the attribute identified by {@code name} and return its value.
	 * Return {@code null} if no attribute under {@code name} is found.
	 * @param name the unique attribute key
	 * @return the last value of the attribute, if any
	 */
	@Nullable
	Object removeAttribute(String name);

	/**
	 * Return {@code true} if the attribute identified by {@code name} exists.
	 * Otherwise return {@code false}.
	 * @param name the unique attribute key
	 */
	boolean hasAttribute(String name);

	/**
	 * Return the names of all attributes.
	 */
	String[] attributeNames();

}

4.4 AttributeAccessorSupport属性访问抽象实现类

  内部定义了1个map来存放属性。

public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {

	/** Map with String keys and Object values. */
	private final Map<String, Object> attributes = new LinkedHashMap<>();


	@Override
	public void setAttribute(String name, @Nullable Object value) {
		Assert.notNull(name, "Name must not be null");
		if (value != null) {
			this.attributes.put(name, value);
		}
		else {
			removeAttribute(name);
		}
	}
    //  ......
}

4.5 BeanMetadataAttributeAccessor元数据属性访问器

  继承AttributeAccessorSupport具备属性访问功能,实现BeanMetadataElement具备获取元数据功能。 **AbstractBeanDefinition就继承于它,使得同时具有属性访问和元数据访问的功能 **。

image.png

结合AbstractBeanDefinition.来看看他们的类图结构

image.png

5. BeanDefinition继承体系

5.1 AnnotatedBeanDefinition

  增加了2个方法,获取bean所在类的注解元数据和工厂方法元数据,这些数据在进行解析处理的时候需要用到。

public interface AnnotatedBeanDefinition extends BeanDefinition {

	/**
	 * Obtain the annotation metadata (as well as basic class metadata)
	 * for this bean definition's bean class.
	 * @return the annotation metadata object (never {@code null})
	 */
	AnnotationMetadata getMetadata();

	/**
	 * Obtain metadata for this bean definition's factory method, if any.
	 * @return the factory method metadata, or {@code null} if none
	 * @since 4.1.1
	 */
	@Nullable
	MethodMetadata getFactoryMethodMetadata();

}

  该注解有三个具体的实现。ScannedGenericBeanDefinition、AnnotatedGenericBeanDefinition、ConfigurationClassBeanDefinition。

image.png

5.2 AbstractBeanDefinition模板类

  AbstractBeanDefinition我们可以称之为BeanDefinition的模板类。结构我们上面其实有梳理

image.png

  通过上面我们可以看到AbstractBeanDefinition 具备了 Bean元数据的获取和属性相关的操作。同时AbstractBeanDefinition的继承结构

image.png

5.3 RootBeanDefinition根bean定义

  它主要用在spring内部的bean定义、把不同类型的bean定义合并成RootBeanDefinition(getMergedLocalBeanDefinition方法)。没有实现BeanDefinition接口的设置获取父bean定义方法,不支持设置父子beanDefinition。

5.4 ConfigurationClassBeanDefinition

  用作ConfigurationClassPostProcessor解析过程中封装配置类的bean定义。

5.5 GenericBeanDefinition

  GenericBeanDefinition通用Bean的定义。

5.6 ScannedGenericBeanDefinition

  @ComponentScan扫描的bean定义使用。

5.7 AnnotatedGenericBeanDefinition

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1124798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光环云入选“北京市算力互联互通试点参与企业”!

为进一步贯彻落实工业和信息化部等六部委联合印发的《算力基础设施高质量发展行动计划》&#xff0c;扩大北京市算力互联互通试点参与范围&#xff0c;助力建设全球数字经济标杆城市&#xff0c;北京市通信管理局组织相关专家对申报第二批参与试点企业开展评估&#xff0c;光环…

docker 部署服务案例

mysql Centos7为例 NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI_COLOR"0;31" CPE_NAME"cpe:/o:centos:cento…

mysql之通过表名来搜索库名

1、经常遇到查日志时候知道表名&#xff0c;但是不知道在哪个库下面&#xff0c;可以通过此sql语句查询。 SELECT * FROM information_schema.TABLES WHERE table_name tb_xxxxxx;

python之代理ip的配置与调试方法详解

代理IP在Python中是一种强大的工具&#xff0c;它可以用于隐藏真实IP地址、绕过访问限制、提高数据爬取和网络请求的效率等。下面将详细介绍Python中代理IP的配置与调试方法&#xff0c;帮助您更好地理解和应用代理IP。 1. 选择合适的代理IP 在使用代理IP之前&#xff0c;需要…

vtk 多边形绘制 vtkPolygon 三角形 矩形 多边形

vtk 可以通过 vtkPolygon 绘制 三角形 矩形 多边形 目录 vtk 可以通过 vtkPolygon 绘制 三角形 矩形 多边形 效果&#xff1a; 源码&#xff1a; 效果&#xff1a; 三角形 矩形&#xff1a; 多边形&#xff1a; 源码&#xff1a; #include "vtkAutoInit.h" VTK_M…

通过电脑操作安卓手机数据恢复最好的几个工具

在本次评测中&#xff0c;我将介绍适用于 PC (Windows 10/11) 的最佳 Android 数据恢复软件&#xff0c;它可以帮助您从通过 MTP 连接的手机或平板电脑上恢复文件和数据。 2023 年适用于 PC 和 Mac 的最佳安卓数据恢复软件 1、U1tData安卓数据恢复&#xff08;奇客软件&#xf…

599L是什么芯片,sot23-6封装591NW

60转5v-599L芯片具有以下特点&#xff1a; - 600mA的连续输出电流能力 - 宽输入工作范围&#xff0c;从4.5V至60V - 集成了80V、550mQ高侧和80V、350mQ低侧功率MOSFET开关 - 高达95%的效率 - 内部软启动功能&#xff0c;限制开机时的浪涌电流 - 内部补偿功能&#xff0c;减少外…

程序员空闲时间能不能找其他副业?还是该继续卷技术?

我认为这是个伪命题&#xff01;程序员都在996/007&#xff0c;哪来的空闲时间&#xff0c;这是让他们不睡觉吗&#xff1f; 那些有空闲时间的程序员应该是还没找到工作的程序员吧&#xff01;主业都没有&#xff0c;谈什么副业。 假如有少部分人&#xff0c;是属于985的程序…

超实用的跟圈和一键转发好友朋友圈功能

一键转发朋友圈/跟圈 想转发别人的朋友圈内容&#xff0c;通常需要手动复制粘贴&#xff0c;一个个复制保存实在是太麻烦耗费时间。 有时候咱也不可能随时都看朋友圈嘛&#xff0c;那又想及时转发朋友的圈的&#xff0c;有什么办法可以轻松实现呢&#xff1f; 操作步骤 单击…

黑客为什么不 入侵银行一夜暴富

前言 厉害的黑客只需要入侵银行系统&#xff0c;改动一下自己账户余额数字&#xff0c;身家不就可以轻松过亿了吗&#xff1f; 然而事实却是没有哪个黑客做成这件事。大家要知道&#xff0c;银行的网站和网上银行系统是分开部署的。黑客成功入侵了银行的网站&#xff0c;他能…

推荐一款可以识别m3u8格式ts流批量下载并且合成mp4视频的chrome插件——猫抓

https://chrome.google.com/webstore/detail/%E7%8C%AB%E6%8A%93/jfedfbgedapdagkghmgibemcoggfppbb?utm_sourceext_app_menuhttps://chrome.google.com/webstore/detail/%E7%8C%AB%E6%8A%93/jfedfbgedapdagkghmgibemcoggfppbb?utm_sourceext_app_menu 网页媒体嗅探工具 一…

(十一)Python模块和包

前面章节中&#xff0c;我们已经使用了很多模块&#xff08;如 string、sys、os 等&#xff09;&#xff0c;通过向程序中导入这些模块&#xff0c;我们可以使用很多“现成”的函数实现想要的功能。 那么&#xff0c;模块到底是什么&#xff0c;模块内部到底是什么样子的&…

生成式AI革命对亚马逊的电商业务是威胁还是机遇?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;当所有人都在关注生成式AI是如何威胁谷歌(GOOG)的搜索业务之际&#xff0c;投资界却忽视了一个事实&#xff0c;即&#xff1a;它也给亚马逊(AMZN)的电商业务带来了威胁。 &…

win10安装 nvm + angular

① 安装nvm② 配置全局的node_modules2.1 新建[node_global] 、[node_cache]文件夹2.2 cmd窗口执行命令&#xff08;设置npm的路径&#xff09;2.3 配置环境变量 ③ 安装angular-cli④ 检查环境版本 指路&#xff0c;简易版安装指南&#xff0c;有安装基础的可以看这里&#xf…

应用3之Like运算符的应用

《VBA经典应用69例》&#xff08;10178981&#xff09;&#xff0c;是我推出的第九套教程&#xff0c;教程是专门针对初级、中级学员在学习VBA过程中可能遇到的案例展开&#xff0c;这套教程案例众多&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以便大家…

自然语言处理---RNN经典案例之构建人名分类器

1 案例介绍 关于人名分类问题&#xff1a;以一个人名为输入, 使用模型帮助判断它最有可能是来自哪一个国家的人名&#xff0c;这在某些国际化公司的业务中具有重要意义&#xff0c;在用户注册过程中&#xff0c;会根据用户填写的名字直接给他分配可能的国家或地区选项&#xff…

高防回源ip被源站拦截怎么办

​  在进行网站运营过程中&#xff0c;我们经常会遇到DDoS攻击等网络安全威胁。为了保护网站的正常运行&#xff0c;很多企业选择使用高防服务来应对这些攻击。有时候我们可能会遇到一个问题&#xff0c;就是高防回源IP被源站拦截的情况。 那么&#xff0c;当我们发现高防回源…

单线程模型想象不到的高并发能力、多路复用是效率杠杆

文章目录 &#x1f34a; 多路复用&#x1f389; redis的多路复用模式&#x1f4dd; 应用对外提供服务的过程&#x1f4dd; select&#x1f4dd; epoll&#x1f4dd; 多路复用的定义&#x1f4dd; 多路复用的举例&#x1f4dd; 多路复用的实现&#x1f525; 过程一&#xff1a;数…

a-table 修改默认的空状态描述

1 默认的空状态样式 simple图片和暂无数据样式 a-table api 意思是修改了local属性中的emptyText就可以改变内容了 :loacl"{emptyText:自定义内容}"但是这样写的话 就不显示图片了 可以使用a-empty 来自定义 2 空状态样式修改 :loacl"loacl" data(){re…

【华为路由器】配置企业通过5G链路接入Internet示例

场景介绍 5G Cellular接口是路由器用来实现5G技术的物理接口&#xff0c;它为用户提供了企业级的无线广域网接入服务&#xff0c;主要用于eMBB场景。与LTE相比&#xff0c;5G系统可以为企业用户提供更大带宽的无线广域接入服务。 路由器的5G功能&#xff0c;可以实现企业分支…