简单实现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里没有单例对象.

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

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

相关文章

MySQL行锁范围分析(行锁、间隙锁、临键锁)

MySQL 中锁的概念 排它锁&#xff08;Exclusive Lock&#xff09; X 锁&#xff0c;也称为写锁&#xff0c;若事务T对对象A加上X锁&#xff0c;则只允许T读取和修改A&#xff0c;其他任何事物都不能再对A 加任何锁&#xff0c;直到T释放A上的锁。 SELECT…FOR UPDATE 对读取的…

风控之Android设备指纹技术

标识性参数——Android ID、IMEI、OAID非标识性参数 非标识性参数——手机运营商 1 设备指纹 简单来讲&#xff0c;设备指纹是指用于标识出该设备的设备特征。可以是单一设备特征&#xff0c;也可以是多种设备特征的组合&#xff0c;以方便风控系统对设备的唯一性进行识别。…

产品入门第一讲:Axure的安装以及基本使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有…

未来教师行业发展前景

亲爱的老师们&#xff0c;你是否对未来教师行业的发展前景感到好奇和期待&#xff1f;作为一名老师&#xff0c;我深知教育行业的重要性和挑战&#xff0c;但同时也看到了其中蕴含的巨大机遇。 一、技术融合与在线教育 技术的飞速发展正在改变着教育的面貌。在线教育平台的崛起…

用C语言了解文件那些下 ‘流‘ 事

本篇会加入个人的所谓‘鱼式疯言’❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的&#xff0c;可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 前言 &#…

uniapp实战 —— 自定义顶部导航栏

效果预览 下图中的红框区域 范例代码 src\pages.json 配置隐藏默认顶部导航栏 "navigationStyle": "custom", // 隐藏默认顶部导航src\pages\index\components\CustomNavbar.vue 封装自定义顶部导航栏的组件&#xff08;要点在于&#xff1a;获取屏幕边界…

OpenAI在中国,申请GPT-6、GPT-7商标

根据最新商标信息显示&#xff0c;OpenAI已经在中国提交了GPT-6和GPT-7的商标注册信息&#xff0c;分类是科学仪器和网站服务两大类。申请日期是今年的11月2日&#xff0c;目前处于审核状态。 该申请由知识产权代理公司完成&#xff0c;但申请人的地址正是OpenAI在美国公司的地…

Echarts图表title使用富文本

rich中有配置的话&#xff08;如a&#xff09;使用该样式&#xff0c;没有配置样式的话&#xff08;如b&#xff09;使用外层textstyle的样式&#xff0c;textstyle没有样式的话使用默认样式 const option1 {tooltip: {trigger: "item",},title: {text: ["{a|1…

Java代码审计之SpEL表达式注入漏洞分析

文章目录 前言SpEL表达式基础基础用法安全风险案例演示 CVE-2022-22963漏洞简述环境搭建反弹shell CVE漏洞调试分析本地搭建调试分析补丁分析 总结 前言 表达式注入是 Java 安全中一类常见的能够注入命令并形成 RCE 的漏洞&#xff0c;而常见的表达式注入方式有 EL 表达式注入…

124.(leaflet篇)leaflet禁止地图移动,缩放,双击

地图之家总目录(订阅之前必须详细了解该博客) 完整代码工程包下载,运行如有问题,可“私信”博主。效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【Docker】使用docker-compose搭建django+vue工程文章

我们尝试使用docker-compose编排一个后端基于django,前端基于vue,数据库为postgresql并使用nginx进行反向代理的web工程。 工程准备 Docker 安装Docker 安装docker-compose django 在python3.7的环境下创建 修改settings.py文件 修改 将静态文件收集路径添加进 ,笔…

pip指定优先从豆瓣源下载包

对于 Unix/macOS 系统&#xff0c;使用以下命令&#xff1a; pip config set global.index-url https://pypi.douban.com/simple/ 对于 Windows 系统&#xff0c;打开命令提示符或PowerShell&#xff0c;并使用相同的命令&#xff1a; pip config set global.index-url http…

XUbuntu22.04之8款免费UML工具(一百九十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

供应链管理痛点大解析!内附解决方案

供应链是指涉及产品或服务生产、运输、分销和最终交付给客户的过程。 用一个汽车制造的例子来帮助大家理解&#xff1a; 原材料采购&#xff1a; 汽车制造商需要从供应商处采购制造汽车所需的原材料&#xff0c;例如金属、橡胶、塑料和玻璃。生产制造&#xff1a;获得原材料&…

UnoCSS 原子化开发初体验

UnoCSS 是一个即时的原子化 CSS 引擎&#xff0c;旨在灵活和可扩展。核心是不拘一格的&#xff0c;所有的 CSS 工具类都是通过预设提供的。再也不用为了取一个 classname 类名而烦恼了。 一、UnoCSS 特点 完全可定制&#xff1a;无核心工具&#xff0c;所有功能都通过预设提供…

如何公网访问内网的群晖NAS随时随地远程访问本地存储的学习资源

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

成都工业学院Web技术基础(WEB)实验六:ECMAScript基础语法

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考&#xff0c;前端变化比较大&#xff0c;按照要求&#xff0c;只能做到像&#xff0c;不能做到一模一样 3、图片和文字仅为示例&#xff0c;需要自行替换 4、如果代码不满足你的要求&#xff0c;请寻求其他的…

TwinCAT3 Modbus-TCP Client/Server使用

目录 一、环境配置和准备 1、PLC中安装TF6250-Modbus-TCP库 2、勾选TF6250的license 3、PLC工程中添加Tc2_ModbusSrv库文件 4、分别创建测试ModbusTCP测试的Server和Client程序 二、PLC作为Client端 1、设置测试电脑IP地址 2、运行MobusTCP测试工具 3、PLC端程序编写 …

Hiera实战:使用Hiera实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

可学习超图拉普拉斯算子代码

python版本&#xff1a;3.6。sklearn版本&#xff1a;scikit-learn0.19 问题1&#xff1a;ERROR: Could not build wheels for ecos, scs, which is required to install pyproject.toml-based projects| 解决办法&#xff1a;cvxpy安装过程中遇到的坑_ecos 2.0.7.post1 cp37 …