当前位置: 首页 > news >正文

Spring-手写模拟Spring底层原理

概述

模拟大致的底层原理,为学习Spring源码做铺垫。

实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面

未实现的功能:构造器推断、循环依赖

重点:BeanDefinition、BeanPostProcessor

学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点

启动类:

public class Yeah
{public static void main(String[] args){GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");userService.test();}
}

关键方法:

public class GaxApplicationContext
{private Class configClass;private static final String SINGLETON = "singleton";private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();private Map<String, Object> singletonObjects = new HashMap<>();// Spring源码用的是LinkedListprivate List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();public GaxApplicationContext(Class configClass){this.configClass = configClass;// 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中scan(configClass);// 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()){String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();if (SINGLETON.equals(beanDefinition.getScope())){Object bean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, bean);}}}private Object createBean(String beanName, BeanDefinition beanDefinition){Class clazz = beanDefinition.getType();Object instance = null;try{// 直接使用默认的无参构造器,多个构造器的场景未实现instance = clazz.getConstructor().newInstance();// 属性填充,依赖注入for (Field field : clazz.getDeclaredFields()){if (field.isAnnotationPresent(Autowired.class)){field.setAccessible(true);field.set(instance, getBean(field.getName()));}}// aware回调if (instance instanceof BeanNameAware){((BeanNameAware)instance).setBeanName(beanName);}// 初始化前for (BeanPostProcessor beanPostProcessor : beanPostProcessorList){instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}// 初始化if (instance instanceof InitializingBean){((InitializingBean)instance).afterPropertiesSet();}// 初始化后for (BeanPostProcessor beanPostProcessor : beanPostProcessorList){instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}}catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e){e.printStackTrace();}return instance;}public Object getBean(String beanName){if (!beanDefinitionMap.containsKey(beanName)){throw new NullPointerException();}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (SINGLETON.equals(beanDefinition.getScope())){Object singletonBean = singletonObjects.get(beanName);if (null == singletonBean){singletonBean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, singletonBean);}return singletonBean;}else{// 原型BeanObject prototypeBean = createBean(beanName, beanDefinition);return prototypeBean;}}private void scan(Class configClass){if (configClass.isAnnotationPresent(ComponentScan.class)){ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);String path = componentScanAnnotation.value();// path = com/gax/servicepath = path.replace(".", "/");ClassLoader classLoader = GaxApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);assert resource != null;File file = new File(resource.getFile());if (file.isDirectory()){for (File f : Objects.requireNonNull(file.listFiles())){String absolutePath = f.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));// 类加载器入参需要的格式:com.gax.service.XXXabsolutePath = absolutePath.replace("\\", ".");try{Class<?> clazz = classLoader.loadClass(absolutePath);if (clazz.isAnnotationPresent(Component.class)){if (BeanPostProcessor.class.isAssignableFrom(clazz)){BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}Component componentAnnotation = clazz.getAnnotation(Component.class);String beanName = componentAnnotation.value();if ("".equals(beanName)){// 默认beanNamebeanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(clazz);if (clazz.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = clazz.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);}else{// 默认单例BeanbeanDefinition.setScope(SINGLETON);}beanDefinitionMap.put(beanName, beanDefinition);}}catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException| InstantiationException | IllegalAccessException e){e.printStackTrace();}}}}}
}

gitee地址:

git clone https://gitee.com/seek6174/spring-seek.git

相关文章:

Spring-手写模拟Spring底层原理

概述 模拟大致的底层原理&#xff0c;为学习Spring源码做铺垫。 实现的功能&#xff1a;扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面 未实现的功能&#xff1a;构造器推断、循环依赖 重点&#xff1a;BeanDefinition、BeanPostProcessor 学习Spring…...

Scala【集合常用方法和函数操作(下)】

Fold、FoldLeft 和 FoldRight object Test03_Fold {def main(args: Array[String]): Unit {// 称作集合外的参数val list List(1,2,3,4)// fold的底层仍然是调用的 foldLeft// 第一个参数是一个值(称作集合内的参数&#xff0c;必须和集合外的参数类型一致)// 第二个参数是一…...

JS加密/解密之那些不为人知的基础逻辑运算符

不多说&#xff0c;直接上干货 使用逻辑非运算符 ! 和双重逻辑非运算符 !!&#xff1a;例如 ![]、!![]、!0、!!0 和 !""、!!""。空字符串的转换&#xff1a;!"" 和 !!""。数组和对象的类型转换&#xff1a;[] []、[] - []、{} [] 和…...

flinksql kafka到mysql累计指标练习

flinksql 累计指标练习 数据流向&#xff1a;kafka ->kafka ->mysql 模拟写数据到kafka topic&#xff1a;wxt中 import com.alibaba.fastjson.JSONObject; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.Produ…...

pdf转jpg的方法【ps和工具方法】

pdf转jpg的方法&#xff1a; 1.photoshop办法&#xff1a; pdf直接拖入ps中&#xff0c;另存为*.Jpg文件即可 另外注意的时候&#xff0c;有时候别人给你pdf文件中包含你需要的jpg文件&#xff0c;千万不要截图进入ps中&#xff0c;直接把文件拖入ps中&#xff0c;这样的文件…...

【已解决】Qt发送信号后,槽函数没有响应

Qt发送信号后&#xff0c;槽函数没有响应 检查有没有连接正确的信号和槽函数&#xff0c;有时候&#xff0c;大意了&#xff0c;会写错检查connect函数返回值&#xff0c;有没有连接成功检查对象的创建方式&#xff0c;确保在信号发送前&#xff0c;以及槽函数接收前&#xff…...

Kafka入门05——基础知识

目录 副本数据同步原理 HW和LEO的更新流程 第一种情况 第二种情况 数据丢失的情况 解决方案 Leader副本的选举过程 日志清除策略和压缩策略 日志清除策略 日志压缩策略 Kafka存储手段 零拷贝&#xff08;Zero-Copy&#xff09; 页缓存&#xff08;Page Cache&…...

WordPress(7)配置邮箱发送功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、注册登陆163邮箱1. 配置SMTP二、开启smtp1.添加授权码二.在网站中配置smtp服务1.在主题的Boxmoe主题设置中开启邮箱设置三.安装所需要的插件1.安装完毕开启插件即可四.SMTP邮箱服务测试总结…...

简化路径(C++解法)

题目 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&#xff0c;一个点&#xff08;.&#xff09;表示当前目录本身&#xff1…...

CS224W1.1——图机器学习介绍

文章目录 1. 介绍2. 主要问题3. 深度学习如何应用在图结构中4. 课程大纲 学习一下斯坦福CS224W的图机器学习&#xff08;2021年&#xff09;&#xff0c;并做一下学习笔记&#xff0c;主要是研究方向与图神经网络相关。这次是第一次笔记&#xff0c;图片很多都是从斯坦福的PPT里…...

docker搭建waline评论系统

我这里是给博客网站嵌入评论系统的 1.登录LeanCloud 国际版&#xff0c;没有账号可以注册个 链接&#xff1a;点击跳转 2.新建应用&#xff0c;选择开发版&#xff08;免费&#xff09;&#xff0c;商用版每个月最低消费5美刀。 3.在设置-应用凭证里面将AppID、AppKey、Maste…...

sql server 生成连续日期和数字

在sqlserver里&#xff0c;可以利用系统表master..spt_values里面存储的连续数字0到2047&#xff0c;结合dateadd&#xff08;&#xff09;函数生成连续的日期 select convert (varchar(10),dateadd(d, number, getdate()),23) as workday from master..spt_values where type…...

太极v14.0.4 免ROOT用Xposed

一个帮助你免 Root、免解锁免刷机使用 Xposed 模块的 APP 框架。 模块通过它改变系统和应用的行为&#xff0c;既能以传统的 Root/ 刷机方式运作&#xff0c; 也能免 Root/ 免刷机运行&#xff1b;并且它支持 Android 5.0 ~ 11。 简单来说&#xff0c;太极就是个 Xposed 框架…...

python DevOps

在云原生中&#xff0c;python扮演的角色是什么&#xff1f; 在云原生环境中&#xff0c;Python 作为一种高级编程语言&#xff0c;在多个方面扮演着重要角色。云原生是指利用云计算的各种优势&#xff08;如弹性、可扩展性和自动化&#xff09;&#xff0c;构建和运行应用程序…...

Git(四)底层命令:git对象、树对象、提交对象

目录 一、知识回顾1.1 Linux 基础命令1.2 .git 文件夹解析 二、git 对象&#xff08;数据对象&#xff09;2.1 hash-object 存储对象2.2 cat-file 查看对象 三、树对象3.1 ls-files 查看暂存区3.2 update-index 创建暂存区3.3 write-tree 生成树对象3.4 更新暂存区&#xff0c;…...

LVS-DR模式+keepalived+nginx+tomcat实现动静分离、负载均衡、高可用实验

实验条件&#xff1a; test2——20.0.0.20——主服务器——ipvsadm、keepalived服务 test3——20.0.0.30——备服务器——ipvsadm、keepalived服务 nginx5——20.0.0.51——后端真实服务器1&#xff08;tomcat的代理服务器&#xff09;——nginx服务 nginx6——20.0.0.61—…...

canvas 状态管理

本文简介 带尬猴&#xff0c;我是德育处主任 canvas 绘图时会根据当前状态来绘制。很多的 canvas 库都利用到这一特性。比如 p5.js 利用了 canvas 状态特性衍生出 push 和 pop 函数实现状态隔离&#xff08;既然提到了&#xff0c;下一篇就讲这个&#xff09;。 有兴趣了解 p…...

vue中如何给后端过来的数组中每一个对象加一个新的属性和新的对象(不影响后端的原始数据)

方法&#xff1a; 先看后端的原数据 1、给数组中每一个对象加一个新的属性&#xff1a; 输出查看数组list的值&#xff1a; 2、给数组list加入新的对象&#xff1a; 输出结果&#xff1a; 3、总结&#xff1a; 如果是数组中每个对象新增属性就用map遍历每个对象加入新增的属性…...

SpringAOP源码解析之TargetSource(四)

前言 在Spring框架中&#xff0c;TargetSource是一个接口&#xff0c;用于封装获取目标对象&#xff08;也就是被代理的对象&#xff09;的逻辑。它的主要作用是提供代理对象使用的目标对象&#xff0c;并且允许在运行时动态地切换目标对象。TargetSource在Spring的AOP&#x…...

Centos7 安装nvidia显卡驱动

参考一&#xff1a;https://blog.csdn.net/awen19921106/article/details/131331450 参考二&#xff1a;https://www.cnblogs.com/lishanyang/p/17326021.html 报错一&#xff1a; ERROR: Unable to find the kernel source tree for the currently running kernel. Please …...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...