简单实现Spring容器(二) 封装BeanDefinition对象放入Map
阶段2:
// 1.编写自己的Spring容器,实现扫描包,得到bean的class对象.2.扫描将 bean 信息封装到 BeanDefinition对象,并放入到Map.
思路:
1.将 bean 信息封装到 BeanDefinition对象中,再将其放入到BeanDefinitionMap集合中,集合的结构大概是
key[beanName]–value[beanDefintion]
key--------->对应指定的名字,未指定则以类的首字母小写为其名字
value------->对应封装好的BeanDefintion对象
2.因为bean的作用域可能是singleton,也可能是prototype,所以Spring需要扫描到bean信息,保存到集合,这样当getBean()根据实际情况处理.
具体实现
1.加一个自定义Scope注解
package com.elf.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author 45~* @version 1.0* Scope 可以指定一个Bean的作用范围[singleton,prototype]*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {//通过value可以指定singleton,prototypeString value() default "";
}
2.在MonsterService.java上加上@Scope多实例注解
package com.elf.spring.component;
import com.elf.spring.annotation.Component;
import com.elf.spring.annotation.Scope;/*** @author 45~* @version 1.0* 说明 MonsterService 是一个Servic*/
@Component //把MonsterService注入到我们自己的spring容器中
@Scope(value = "prototype")
public class MonsterService {}
3.准备ioc包下写一个BeanDefinition.java 用于封装记录Bean信息.
package com.elf.spring.ioc;/*** @author 45~* @version 1.0* BeanDefinition 用于封装和记录Bean的信息 [1.scope 2.存放bean对应的Class对象,反射可以生成对应的对象]* 2:因为将来getBean()时有可能是多实例,有可能是动态生成的,还要存放bean的class对象*/
public class BeanDefinition {private String scope;private Class clazz;//存放bean的class对象public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public Class getClazz() {return clazz;}public void setClazz(Class clazz) {this.clazz = clazz;}@Overridepublic String toString() {return "BeanDefinition{" +"scope='" + scope + '\'' +", clazz=" + clazz +'}';}
}
3.pom.xml文件引入jar包下的工具类commons-lang,完成首字母小写的功能.而不用springframework自带的StringUtils工具类

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.elf</groupId><artifactId>elf-myspring1207</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency></dependencies></project>
4.容器文件,把构造器里边的方法抽取出来封装成一个方法,直接在构造器中调用,使代码简洁.
这里完成生成BeanDefinition对象并放入到Map里面
添加内容1:
//定义属性BeanDefinitionMap -> 存放BeanDefinition对象(多例对象)private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();//定义属性SingletonObjects -> 存放单例对象 (跟原生容器的名字保持一致)//因为将来存放单例池的时候肯定要指定单例对象是对应哪个Bean的,所以k用String来充当//存放单例对象的类型是不确定的,可能是Dog,Cat,或者其他的对象,所以用Objectprivate ConcurrentHashMap<String,Object> singletonObjects =new ConcurrentHashMap<>();
添加内容2:
//先得到beanName(有可能通过经典4注解,例如Component注解的value值来指定)//1.得到类上的Component注解,此时的clazz已经是当前bean的class对象,通过类加载器得到的 反射知识Component componentAnnotation = cla.getDeclaredAnnotation(Component.class);//2.得到配置的valueString beanName = componentAnnotation.value();if("".equals(beanName)){//如果没有写value,空串//将该类的类名首字母小写作为beanName//StringUtils其实是在springframework的框架下面的类,而这里本身我就是要自己写所以不用beanName = StringUtils.uncapitalize(className);}//3.将Bean的信息封装到BeanDefinition对象中,然后将其放入到BeanDefinitionMap集合中BeanDefinition beanDefinition = new BeanDefinition();//!!!多看看这里多理解beanDefinition.setClazz(cla);//由类加载器通过反射得到对象,Class<?> cla = classLoader.loadClass(classFullName);//4.获取Scope值if (cla.isAnnotationPresent(Scope.class)){//如果配置了Scope,就获取它配置的值Scope scopeAnnotatiion = cla.getDeclaredAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotatiion.value());}else{//如果没有配置Scope,就以默认的值singletonbeanDefinition.setScope("singleton");}//将beanDefinitionMap对象放入MapbeanDefinitionMap.put(beanName,beanDefinition);}else {//如果该类没有使用了@Component注解,说明是一个Spring beanSystem.out.println("这不是一个Spring bean" + cla + " 类名=" + className);}
容器文件
package com.elf.spring.ioc;import com.elf.spring.annotation.*;
import org.apache.commons.lang.StringUtils;import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;/*** @author 45~* @version 1.0*/
public class ElfSpringApplicationContext {//第一步,扫描包,得到bean的class对象,排除包下不是bean的,因此还没有放到容器中//因为现在写的spring容器比原先的基于注解的,要更加完善,所以不会直接把它放在ConcurrentHashMapprivate Class configClass;//定义属性BeanDefinitionMap -> 存放BeanDefinition对象private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();//定义属性SingletonObjects -> 存放单例对象 (跟原生容器的名字保持一致)//因为将来存放单例池的时候肯定要指定单例对象是对应哪个Bean的,所以k用String来充当//存放单例对象的类型是不确定的,可能是Dog,Cat,或者其他的对象,所以用Objectprivate ConcurrentHashMap<String,Object> singletonObjects =new ConcurrentHashMap<>();//构造器public ElfSpringApplicationContext(Class configClass) {beanDefinitionScan(configClass);//调用封装方法,简洁System.out.println("beanDefinitionMap=" + beanDefinitionMap);}//构造器结束//该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition对象,再放入到Map中public void beanDefinitionScan(Class configClass){this.configClass = configClass;/**获取要扫描的包:1.先得到ElfSpringConfig配置的 @ComponentScan(value= "com.elf.spring.component")2.通过 @ComponentScan的value => 即要扫描的包 **/ComponentScan componentScan =(ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);String path = componentScan.value();System.out.println("要扫描的包path=" + path);/*** 得到要扫描包下的所有资源(类.class)* 1.得到类的加载器 -> APP类加载器是可以拿到 target目录下的classes所有文件的* 2.通过类的加载器获取到要扫描的包的资源url => 类似一个路径* 3.将要加载的资源(.class)路径下的文件进行遍历 => io*/ClassLoader classLoader = ElfSpringApplicationContext.class.getClassLoader();path = path.replace(".", "/"); // 把.替换成 /URL resource = classLoader.getResource(path);System.out.println("resource=" + resource);File file = new File(resource.getFile());if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) { //把所有的文件都取出来System.out.println("============================");System.out.println("f.getAbsolutePath()=" + f.getAbsolutePath());String fileAbsolutePath = f.getAbsolutePath();//到target的classes目录下了//这里只处理.class文件if (fileAbsolutePath.endsWith(".class")) {//1.获取类名String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1,fileAbsolutePath.indexOf(".class"));//2.获取类的完整路径(全类名)String classFullName = path.replace("/", ".") + "." + className;System.out.println("classFullName=" + classFullName);//3.判断该类是否需要注入,就看是不是有注解@Component @Service @Contoller @Re....try {Class<?> cla = classLoader.loadClass(classFullName);if (cla.isAnnotationPresent(Component.class) ||cla.isAnnotationPresent(Controller.class) ||cla.isAnnotationPresent(Service.class) ||cla.isAnnotationPresent(Repository.class)) {//演示机制//如果该类使用了@Component注解,说明是一个Spring beanSystem.out.println("这是一个Spring bean=" + cla + " 类名=" + className);//先得到beanName(有可能通过经典4注解,例如Component注解的value值来指定)//1.得到类上的Component注解,此时的clazz已经是当前bean的class对象,通过类加载器得到的 反射知识Component componentAnnotation = cla.getDeclaredAnnotation(Component.class);//2.得到配置的valueString beanName = componentAnnotation.value();if("".equals(beanName)){//如果没有写value,空串//将该类的类名首字母小写作为beanName//StringUtils其实是在springframework的框架下面的类,而这里本身我就是要自己写所以不用beanName = StringUtils.uncapitalize(className);}//3.将Bean的信息封装到BeanDefinition对象中,然后将其放入到BeanDefinitionMap集合中BeanDefinition beanDefinition = new BeanDefinition();//!!!多看看这里多理解beanDefinition.setClazz(cla);//由类加载器通过反射得到对象,Class<?> cla = classLoader.loadClass(classFullName);//4.获取Scope值if (cla.isAnnotationPresent(Scope.class)){//如果配置了Scope,就获取它配置的值Scope scopeAnnotatiion = cla.getDeclaredAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotatiion.value());}else{//如果没有配置Scope,就以默认的值singletonbeanDefinition.setScope("singleton");}//将beanDefinitionMap对象放入MapbeanDefinitionMap.put(beanName,beanDefinition);}else {//如果该类没有使用了@Component注解,说明是一个Spring beanSystem.out.println("这不是一个Spring bean" + cla + " 类名=" + className);}} catch (Exception e) {e.printStackTrace();}}}//遍历文件for循环结束System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");}}//编写放法返回容器中的对象public Object getBean(String name) {return null;}
}
运行结果
beanDefinitionMap={
monsterService=BeanDefinition{scope=‘prototype’, clazz=class com.elf.spring.component.MonsterService},
monsterDao=BeanDefinition{scope=‘singleton’, clazz=class com.elf.spring.component.MonsterDao}
}
ok

这里存在一个问题:单例多例对象都是放在beanDefinitionMap, singletonObjects里没有单例对象.
相关文章:
简单实现Spring容器(二) 封装BeanDefinition对象放入Map
阶段2: // 1.编写自己的Spring容器,实现扫描包,得到bean的class对象.2.扫描将 bean 信息封装到 BeanDefinition对象,并放入到Map.思路: 1.将 bean 信息封装到 BeanDefinition对象中,再将其放入到BeanDefinitionMap集合中,集合的结构大概是 key[beanName]–value[beanDefintion…...
信创运维产业的发展与趋势:IT管理的新视角
随着数字化时代的来临,信息技术应用的各个方面都在发生变革。在这个过程中,信创运维产业的发展尤为引人注目。它不仅是数字化转型的关键驱动力,也是国家经济发展的重要支柱。本文将探讨信创运维产业的发展与趋势,以及国家如何管理…...
算法通关村第十七关 | 黄金挑战 | 跳跃游戏
1.跳跃游戏 原题:力扣55. 逐步判断下一步的覆盖范围,根据范围去推断是否能到达终点,不用计较每一步走到哪里。 public boolean canJump(int[] nums) {// 题目规定 nums 长度大于等于1if (nums.length 1) {return true;}int cover 0;// f…...
思科最新版Cisco Packet Tracer 8.2.1安装
思科最新版Cisco Packet Tracer 8.2.1安装 一. 注册并登录CISCO账号二. 下载 Cisco Packet Tracer 8.2.1三. 安装四. 汉化五. cisco packet tracer教学文档六. 正常使用图 前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新…...
【LeetCode热题100】【滑动窗口】找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 示例 1: 输入: s "cbaebabacd", p "…...
logback的使用
1 logback概述 SLF4J的日志实现组件关系图如下所示。 SLF4J,即Java中的简单日志门面(Simple Logging Facade for Java),它为各种日志框架提供简单的抽象接口。 SLF4J最常用的日志实现框架是:log4j、logback。一般有s…...
IntelliJ IDEA无公网远程连接Windows本地Mysql数据库提高开发效率
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,…...
VS Code使用教程
链接远程服务器 https://blog.csdn.net/zhaxun/article/details/120568402 免密登陆服务器 1生成客户机(个人PC)密令 ssh-keygen -t rsa生成的文件在主目录的.ssh文件当中。 查看密令并复制到linux系统当中 cat id_rsa.pub 2复制到服务器中 echo …...
StarRocks数据模型之主键模型(当前版本v3.1)
StarRocks表设计数据模型,有四种:分别是明细模型(Dumplicate Key table),聚合模型(Aggregate table),更新模型(Unique Key table),主键模型&#…...
正确使用React组件缓存
简介 正常来讲的话当我们点击组件的时候,该组件以及该组件的子组件都会重新渲染,但是如何避免子组件重新渲染呢,我们经常用memo来解决 React.memo配合useCallback缓存组件 父组件没有传props const Index ()> {console.log(子组件刷新…...
AMEYA360:大唐恩智浦荣获 2023芯向亦庄 “汽车芯片50强”
2023年11月28日,由北京市科学技术委员会和北京市经济和信息化局指导、北京经济技术开发区管理委员会主办、盖世汽车协办的“芯向亦庄”汽车芯片大赛在北京亦庄成功闭幕。 在本次大赛中 大唐恩智浦的 电池管理芯片DNB1168 (应用于新能源汽车BMS系统) 凭卓越的性能及高…...
在Arch Linux上安装yay
有点麻烦。 准备 # pacman -Syu # pacman -S --needed base-devel git 变身为普通用户 不能使用root下载代码。所以要变身为普通用户: # sueradd tsit # su tsit 下载代码 $ git clone https://aur.archlinux.org/yay.git 编译安装 $ cd yay $ makepkg -si…...
PHP案例:探究MySQL应用开发喜好的网络调查
文章目录 一、知识准备(一)数据库与表的创建(二)录入调查选项(三)创建问卷页面(四)处理投票数据(五)显示调查结果二、实现步骤(一)创建数据库与表(二)录入若干调查选项(三)创建问卷页面(四)创建调查结果页面(五)体验运行结果(六)查看最终生成的HTML代码很…...
力扣第374场周赛题解
这一场周赛的题目是比较难的一次,写了1个多小时就写了两个题目。 首先第一题: 纯水题,遍历然后进行一下判断就可以解决了。这边就不放代码了。 第二题: 这个题目,我觉得难度非常大,其实代码量也不大都是很…...
Linux Docker 安装Nginx
1.21、查看可用的Nginx版本 访问Nginx镜像库地址:https://hub.docker.com/_/nginx 2、拉取指定版本的Nginx镜像 docker pull nginx:latest #安装最新版 docker pull nginx:1.25.3 #安装指定版本的Nginx 3、查看本地镜像 docker images 4、根据镜像创建并运行…...
鸿蒙应用开发(二)环境搭建
开发流程 IDE下载 首先下载HUAWEI DevEco Studio,介绍首次启动DevEco Studio的配置向导: 运行已安装的DevEco Studio,首次使用,请选择Do not import settings,单击OK。安装Node.js与ohpm。node.js 是基于 V8 引擎构…...
在 Qt Creator 中编写 Doxygen 风格的注释
2023年12月10日,周日上午 如何生成Doxygen 风格的注释 在需要Doxygen 风格注释的函数上方输入 /**,然后按下 Enter 键。Qt Creator 将自动为你生成一个注释模板。 输入,Qt Creator会自动帮你补全Doxygen标签 不得不说,写了Doxyge…...
NSS [NSSCTF 2022 Spring Recruit]babyphp
NSS [NSSCTF 2022 Spring Recruit]babyphp 考点:PHP特性 开局源码直接裸奔 <?php highlight_file(__FILE__); include_once(flag.php);if(isset($_POST[a])&&!preg_match(/[0-9]/,$_POST[a])&&intval($_POST[a])){if(isset($_POST[b1])&&…...
ToolkenGPT:用大量工具增强LLM
深度学习自然语言处理 原创作者:cola 用外部工具增强大型语言模型(LLM)已经成为解决复杂问题的一种方法。然而,用样例数据对LLM进行微调的传统方法,可能既昂贵又局限于一组预定义的工具。最近的上下文学习范式缓解了这一问题,但有…...
2022蓝桥杯c组求和
题目名字 求和 题目链接 题意 输入的每个数都要两两相乘,然后再加起来,求最后总和; 思路 每个数乘这个数的前缀和即可 算法一:前缀和 实现步骤 先把前缀和写出来再写for循环每个数都乘以自己的前缀和; 实现步骤 直接…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
