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

手写Spring框架

手写Spring框架

各位道友,我发现现在贼卷底层代码,看完源码发下几天后,额!!!我当时看了啥!

还是自己写个迷你的spring框架,这样印象更加深刻,上干货,代码仓库:https://gitee.com/smd_somin/SmdSpring.git

上面是我写的迷你版的spring框架,麻雀虽小,五脏俱全,主要包括下边的内容

  • 容器启动
  • BeanDefinition扫描
  • Bean声明周期
  • 单例与多例
  • 依赖注入
  • AOP
  • aware回调
  • 初始化
  • BeanPostProcessor(增强器)

下面是手写框架的过程和思路,仅供大家参考!!!

相信大家总会遇到这样问题,聊聊你理解的spring?

这个基本是100个技术,99个会遇到这个问题?我谈一下我得理解,仅供参考,我认为spring可以用两行表示

    //创建容器SmdApplicationContext context = new SmdApplicationContext(AppConfig.class);//获取对象UserInterface userService = (UserInterface) context.getBean("userService");

在这两行代码所牵连的内容其实就是spring的本质,对与bean的管理。

如果需要容器,那么我们需要有一个容器类,下面是手写spring容器的全部代码,这个也是逻辑的核心内容,下面会分享一下思路(建议对着源码看下):

上面的代码可以整体分为两个步骤,一个创建容器,另一个是从容器中获取bean。

首先说说创建容器的过程

创建容器 -> 扫描.class文件 -> 适配文件路径 -> 判断@Component注解 -> 符合注解进行反射获取对象 -> 记录bean的信息(类型,单例)-> 创建对象 -> 实例化对象 -> 依赖注入 -> aware增强类处理 -> 处理BeanPostProcessor的 postProcessorBeforeInitialazition方法 -> 初始化 -> BeanProcessor的beanPostProcessorAfterInitailzaiton方法 ->处理切面逻辑->bean创建成功

获取bean过程

主要区分单例还是多例,单例从单例池中取,多例新创建一个bean

SmdApplicationContext

package org.smd.spring;import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.smd.spring.annotation.Autowrite;
import org.smd.spring.annotation.Component;
import org.smd.spring.annotation.ScanComponent;
import org.smd.spring.annotation.Scope;
import org.smd.spring.aware.BeanNameAware;
import org.smd.spring.init.InitializingBean;/*** @author smd* @zhName 容器* @description: 容器*/
public class SmdApplicationContext {public Map<String, BeanDefinition> definitionMap = new HashMap();public Map<String, Object> singletonBeanMap = new HashMap();public List<BeanPostProcessor> beanPostProcessors=new ArrayList<BeanPostProcessor>();private Class configClass;public SmdApplicationContext(Class configClass) {this.configClass = configClass;//扫描文件夹下数据if (configClass.isAnnotationPresent(ScanComponent.class)) {ScanComponent scanComponent = (ScanComponent) configClass.getAnnotation(ScanComponent.class);//进行文件路径转化String path = scanComponent.vaule();System.out.println("-->scanComponent:" + path);path = path.replace(".", "/");System.out.println("-->scanComponent:" + path);//加载jar下.class文件ClassLoader classLoader = SmdApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);File file = new File(resource.getFile());if (file.isDirectory()) {for (File f : file.listFiles()) {String filePath = f.getAbsolutePath();System.out.println("--> file path:" + filePath);if (filePath.endsWith(".class")) {String filesName = filePath.substring(filePath.indexOf("org"), filePath.indexOf(".class"));filesName = filesName.replace("\\", ".");System.out.println("-->file name" + filesName);try {Class<?> clazz = classLoader.loadClass(filesName);if (clazz.isAnnotationPresent(Component.class)) {if(BeanPostProcessor.class.isAssignableFrom(clazz)){BeanPostProcessor beanPostProcessor=(BeanPostProcessor) clazz.newInstance();beanPostProcessors.add(beanPostProcessor);}Component component = clazz.getAnnotation(Component.class);//获取bean nameString name = component.vaule();if (name.equals("")) {name = Introspector.decapitalize(clazz.getSimpleName());}//记录bean definitionBeanDefinition definition = new BeanDefinition();definition.setType(clazz);if (clazz.isAnnotationPresent(Scope.class)) {Scope scope = (Scope) clazz.getAnnotation(Scope.class);definition.setScope(scope.value());} else {definition.setScope("singleton");}//放入bean definition map中definitionMap.put(name, definition);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}}}}//初始化beanfor (String name : definitionMap.keySet()) {BeanDefinition definition = definitionMap.get(name);Object bean = this.createBean(name, definition);singletonBeanMap.put(name, bean);}}private Object createBean(String name, BeanDefinition definition) {Class clazz = definition.getType();try {//实例化Object bean = clazz.getConstructor().newInstance();//依赖注入for (Field field : clazz.getDeclaredFields()) {if (field.isAnnotationPresent(Autowrite.class)) {field.setAccessible(true);field.set(bean, getBean(field.getName()));}}// aware加强类回调if(bean instanceof BeanNameAware){((BeanNameAware)bean).setBeanName(name);}// 初始化前调用bean post processorfor (BeanPostProcessor beanPostProcessor : beanPostProcessors) {bean= beanPostProcessor.postProcessorBeforeInitialization(name,bean);}// 初始化if(bean instanceof InitializingBean){((InitializingBean)bean).afterPropertiesSet();}// 初始化后调用bean post processorfor (BeanPostProcessor beanPostProcessor : beanPostProcessors) {bean= beanPostProcessor.postProcessorAftertInitialization(name,bean);}return bean;} catch (Exception e) {e.printStackTrace();}return null;}public Object getBean(String name) {//获取definition信息BeanDefinition definition = definitionMap.get(name);if (definition == null) {System.out.println("-->error:" + name);throw new NullPointerException();} else {//进行单例和多例区分if (definition.getScope().equals("singleton")) {Object bean = singletonBeanMap.get(name);if (bean == null) {return this.createBean(name, definition);} else {return bean;}} else {return this.createBean(name, definition);}}}
}

各位道友前路漫漫~ 努力向远方前进吧!!!

《真常之道,悟者自得,得悟道者,常清静矣。》

相关文章:

手写Spring框架

手写Spring框架 各位道友&#xff0c;我发现现在贼卷底层代码&#xff0c;看完源码发下几天后&#xff0c;额&#xff01;&#xff01;&#xff01;我当时看了啥&#xff01; 还是自己写个迷你的spring框架&#xff0c;这样印象更加深刻&#xff0c;上干货&#xff0c;代码仓…...

微服务学习笔记--(Docker)

目录 初识DockerDcoker的基本操作Dockerfile自定义镜像Docker-ComposeDocker镜像服务 初始Docter 什么是DockerDocker和虚拟机的区别Docker架构安装Docker 初识Docker-什么是docker 项目部署的问题 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰…...

ChatGPT 国内版免费

ChatGPT 是最新的聊天机器人技术&#xff0c;它可以让你更快地完成各种任务。如果你想要一个在国内的免费版本&#xff0c;你来对地方了&#xff01;在这篇文章中&#xff0c;我们将会分享与你 ChatGPT的最新信息&#xff0c;以及在国内使用 ChatGPT 的方法。如果你想要了解更多…...

推荐5个免费好用的UI模板网站!

1、即时设计 即时设计资源广场是一个聚集了大量优秀设计作品和大厂设计系统超过3000个UI组件库的设计师灵感库。该广场每月更新上百个精品模板&#xff0c;且还将这些模板分门别类按不同类型素材进行分类&#xff0c;其丰富的设计资源包括移动设计、网页设计、插画、线框图、矢…...

linux 安装 maven 3.8 版本

文章目录 1&#xff1a;maven 仓库官网 2、下载安装包 3、使用&#xff1a;Xftp 上传到你想放的目录 4、解压文件 ​编辑 5、配置环境变量 ​编辑 6、刷新 /etc/profile 文件 7、查看maven 版本 1&#xff1a;maven 仓库官网 Maven – Download Apache Mavenhttps://mave…...

Redis的三种持久化策略及选取建议

文章目录 Redis的三种持久化策略及选取建议前言RDB&#xff08;快照&#xff09;概述优缺点 AOF&#xff08;追加文件&#xff09;概述优缺点AOF刷盘策略AOF重写 选取正确的持久化策略AOF和RDB的选择AOF与RDB的混合模式AOF重写和RDB持久化的冲突AOF校验机制三种模式的选择建议 …...

力扣LCP 33. 蓄水

LCP 33. 蓄水 给定 N 个无限容量且初始均空的水缸&#xff0c;每个水缸配有一个水桶用来打水&#xff0c;第 i 个水缸配备的水桶容量记作 bucket[i]。有以下两种操作&#xff1a; 升级水桶&#xff1a;选择任意一个水桶&#xff0c;使其容量增加为 bucket[i]1 蓄水&#xff1…...

内网渗透(八十一)之搭建Exchange服务器

搭建Exchange服务器 环境安装准备 1、Windows Server 2012 R2以管理员身份运行Windows Powershell,安装必需的 Windows组件: Install-WindowsFeature NET-Framework-45-Features, Server-Media-Foundation, RPC-over-HTTP-proxy, RSAT-Clustering, RSAT-Clustering-CmdInt…...

web缓存Squid代理服务

缓存网页对象&#xff0c;减少重复请求 squid代理服务器&#xff0c;主要提供缓存加速&#xff0c;应用层过滤控制的功能 代理工作机制 1.代替客户机向网站请求数据&#xff0c;从而可以隐藏用户的真实ip地址 2.将获得的网页数据&#xff08;静态web元素&#xff09;保存到缓…...

vue实现聊天框自动滚动

需求 1、聊天数据实时更新渲染到页面 2、页面高度随聊天数据增加而增加 3、竖向滚动 4、当用户输入聊天内容或者接口返回聊天内容渲染在页面后&#xff0c;自动滚动到底部 5、提供点击事件操控滚动条上下翻动 环境依赖 vue&#xff1a;vue…...

项目中遇到的一些问题总结(六)

Minio Minio是一个开源的分布式对象存储系统&#xff0c;它使用纠删码技术来保护数据。纠删码技术是一种恢复丢失和损坏数据的数学算法&#xff0c;它将数据分块冗余的分散存储在各个节点的磁盘上&#xff0c;从而提供了一定程度的数据可靠性和冗余性。 在Minio中&#xff0c;…...

Linux线程5——生产消费模型

生产消费模型 1个交易场所:超市 2种角色:生产者/消费者 3种关系:生产者和生产者(竞争关系也叫互斥关系),消费者和消费者(竞争关系同样是互斥关系),生产者和消费者(互斥,同步关系:生产完再消费或消费完再生产)。 以上是生产消费模型遵守的“321”原则。 生产者和消…...

Vue + Springboot 文件上传项目笔记(一)

Vue Springboot 文件上传项目笔记&#xff08;一&#xff09; 前端 使用脚手架创建项目 vue create vue_fileuploaddemo等待命令执行完毕添加 element-ui 组件 E:\java\idea_java_maven\vue_fileuploaddemo>yarn add element-ui yarn add v1.22.19 [1/4] Resolving pac…...

【华为OD机试真题2023B卷 JAVA】座位调整

华为OD2023(B卷)机试题库全覆盖,刷题指南点这里 座位调整 知识点迭代 时间限制:1s 空间限制:256MB 限定语言:C(clang11), C++(clang++11), Java(javac 1.8), Python3(3.9), JavaScript Node(12.18.2), Go(1.14.4) 题目描述: 疫情期间课堂的座位进行了特殊的调整,不能出…...

Python 学习 2022.08.28 周日

文章目录 一、 概述1.1&#xff09; 之前写的文章&#xff1a;1.2) 基础点1.3) 配置1.4) Python2 和 Python3 的区别1.5&#xff09; 相关问题跟踪解决1.6) 其他 一、 概述 1.1&#xff09; 之前写的文章&#xff1a; 【Python大系】Python快速教程《Python 数据库 GUI CGI编…...

WEB自动化测试,一定得掌握的8个核心知识点

​ 编辑 写在前面 使用 cypress 进行端对端测试&#xff0c;和其他的一些框架有一个显著不同的地方&#xff0c;它使用 JavaScript 作为编程语言。 传统主流的 selenium 框架是支持多语言的&#xff0c;大多数 QA 会的 python 和 Java 语言都可以编写 selenium 代码&#xff0…...

期末复习总结!!【MySQL】库和表的基本操作 + 增删改查CURD

文章目录 前言一、数据库的基本操作1, 查看库2, 创建库3, 使用库4, 删除库 二、表的基本操作1, 创建表2, 查看表3, 查看表结构4, 删除表 三、增加(Create)四、查询(Retrieve) (重点)1, 全列查询2, 指定列查询3, 查询字段为表达式4, 指定别名5, 去重6, 排序7, 条件查询7.1, 基本…...

线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队

导读 本文是线上问题处理案例系列之一&#xff0c;旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象&#xff0c;逐步定位到数据库连接池保活问题的全过程&#xff0c;并对其中用到的一些知识点进行了总结。 一、问题描述…...

有了 IP 地址,为什么还要用 MAC 地址?

MAC地址等价于快递包裹上的收件人姓名。 MAC地址更多是用于确认对方信息而存在的。就如同快递跨越几个城市来到你面前&#xff0c;快递员需要和你确认一下收件人是否正确&#xff0c;才会把包裹交给你一样。 IP66在线查IP地址位置&#xff1a;https://www.ip66.net/?utm-sour…...

ChatGPT 推出 iOS 应用,支持语音输入,使用体验如何?

最近&#xff0c;OpenAI 宣布推出官方 iOS 应用&#xff0c;允许用户随时随地访问其高人气 AI 聊天机器人&#xff0c;此举也打破了近几个月内苹果 App Store 上充斥似是而非的山寨服务的窘境。 该应用程序是 ChatGPT 的首个官方移动应用程序。ChatGPT 软件程序在去年推出后迅速…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

基于Java项目的Karate API测试

Karate 实现了可以只编写Feature 文件进行测试,但是对于熟悉Java语言的开发或是测试人员,可以通过编程方式集成 Karate 丰富的自动化和数据断言功能。 本篇快速介绍在Java Maven项目中编写和运行测试的示例。 创建Maven项目 最简单的创建项目的方式就是创建一个目录,里面…...

Qt/C++学习系列之列表使用记录

Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件&#xff0c;同步使用QTableWidgetItem进行单元格的设置&#xff0c;最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…...