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

模拟Spring源码思想,手写源码,理解注解

1、BeanDefinition

package com.csdn.myspring;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class BeanDefinition {private String beanName;private Class beanClass;
}

2、扫描包的工具类MyTools

package com.csdn.myspring;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class MyTools {public static Set<Class<?>> getClasses(String pack) {// 第一个class类的集合Set<Class<?>> classes = new LinkedHashSet<Class<?>>();// 是否循环迭代boolean recursive = true;// 获取包的名字 并进行替换String packageName = pack;String packageDirName = packageName.replace('.', '/');// 定义一个枚举的集合 并进行循环来处理这个目录下的thingsEnumeration<URL> dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);// 循环迭代下去while (dirs.hasMoreElements()) {// 获取下一个元素URL url = dirs.nextElement();// 得到协议的名称String protocol = url.getProtocol();// 如果是以文件的形式保存在服务器上if ("file".equals(protocol)) {// 获取包的物理路径String filePath = URLDecoder.decode(url.getFile(), "UTF-8");// 以文件的方式扫描整个包下的文件 并添加到集合中findClassesInPackageByFile(packageName, filePath, recursive, classes);} else if ("jar".equals(protocol)) {// 如果是jar包文件// 定义一个JarFileSystem.out.println("jar类型的扫描");JarFile jar;try {// 获取jarjar = ((JarURLConnection) url.openConnection()).getJarFile();// 从此jar包 得到一个枚举类Enumeration<JarEntry> entries = jar.entries();findClassesInPackageByJar(packageName, entries, packageDirName, recursive, classes);} catch (IOException e) {// log.error("在扫描用户定义视图时从jar包获取文件出错");e.printStackTrace();}}}} catch (IOException e) {e.printStackTrace();}return classes;}private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, final boolean recursive, Set<Class<?>> classes) {// 同样的进行循环迭代while (entries.hasMoreElements()) {// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件JarEntry entry = entries.nextElement();String name = entry.getName();// 如果是以/开头的if (name.charAt(0) == '/') {// 获取后面的字符串name = name.substring(1);}// 如果前半部分和定义的包名相同if (name.startsWith(packageDirName)) {int idx = name.lastIndexOf('/');// 如果以"/"结尾 是一个包if (idx != -1) {// 获取包名 把"/"替换成"."packageName = name.substring(0, idx).replace('/', '.');}// 如果可以迭代下去 并且是一个包if ((idx != -1) || recursive) {// 如果是一个.class文件 而且不是目录if (name.endsWith(".class") && !entry.isDirectory()) {// 去掉后面的".class" 获取真正的类名String className = name.substring(packageName.length() + 1, name.length() - 6);try {// 添加到classesclasses.add(Class.forName(packageName + '.' + className));} catch (ClassNotFoundException e) {// .error("添加用户自定义视图类错误 找不到此类的.class文件");e.printStackTrace();}}}}}}private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {// 获取此包的目录 建立一个FileFile dir = new File(packagePath);// 如果不存在或者 也不是目录就直接返回if (!dir.exists() || !dir.isDirectory()) {// log.warn("用户定义包名 " + packageName + " 下没有任何文件");return;}// 如果存在 就获取包下的所有文件 包括目录File[] dirfiles = dir.listFiles(// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)(file)-> {return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));});// 循环所有文件for (File file : dirfiles) {// 如果是目录 则继续扫描if (file.isDirectory()) {findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);} else {// 如果是java类文件 去掉后面的.class 只留下类名String className = file.getName().substring(0, file.getName().length() - 6);try {// 添加到集合中去// classes.add(Class.forName(packageName + '.' +// className));// 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));} catch (ClassNotFoundException e) {// log.error("添加用户自定义视图类错误 找不到此类的.class文件");e.printStackTrace();}}}}
}

3、MyAnnotationConfigApplicationContext

package com.csdn.myspring;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
public class MyAnnotationConfigApplicationContext {private Map<String, Object> ioc = new HashMap<>();public MyAnnotationConfigApplicationContext() {}public MyAnnotationConfigApplicationContext(String pack) {//遍历包,找到目标类(原材料)Set<BeanDefinition> beanDefinitions = findBeanDefinitions(pack);//根据原材料获取beancreateObject(beanDefinitions);//自动装配autowireObject(beanDefinitions);}public void autowireObject(Set<BeanDefinition> beanDefinitions) {Iterator<BeanDefinition> iterator = beanDefinitions.iterator();while (iterator.hasNext()) {BeanDefinition beanDefinition = iterator.next();Class clazz = beanDefinition.getBeanClass();Field[] declaredFields = clazz.getDeclaredFields();for (Field declaredField : declaredFields) {Autowired annotation = declaredField.getAnnotation(Autowired.class);if (annotation!=null) {Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);if (qualifier!=null) {try {String beanName = qualifier.value();Object bean = getBean(beanName);String fieldName = declaredField.getName();String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);Method method = clazz.getMethod(methodName, declaredField.getType());Object object = getBean(beanDefinition.getBeanName());method.invoke(object, bean);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}Object object = getBean(beanDefinition.getBeanName());}}}}}public Set<BeanDefinition> findBeanDefinitions(String pack) {//获取包下的所有类Set<Class<?>> classes = MyTools.getClasses(pack);Iterator<Class<?>> iterator = classes.iterator();Set<BeanDefinition> beanDefinitions = new HashSet<>();while (iterator.hasNext()) {//2、遍历这些类,找到添加了注解的类Class<?> clazz = iterator.next();Component componentAnnotation = clazz.getAnnotation(Component.class);if (componentAnnotation != null) {//获取Component注解的值String beanName = componentAnnotation.value();if ("".equals(beanName)) {//获取类名首字母小写String className = clazz.getName().replaceAll(clazz.getPackage().getName() + ".", "");beanName = className.substring(0, 1).toLowerCase() + className.substring(1);}//3、将这些类封装成BeanDefinition,装载到集合中beanDefinitions.add(new BeanDefinition(beanName, clazz));}}return beanDefinitions;}public void createObject(Set<BeanDefinition> beanDefinitions) {Iterator<BeanDefinition> iterator = beanDefinitions.iterator();while (iterator.hasNext()) {BeanDefinition beanDefinition = iterator.next();Class clazz = beanDefinition.getBeanClass();String beanName = beanDefinition.getBeanName();try {//创建对象Object object = clazz.getConstructor().newInstance();//完成属性的赋值Field[] declaredFields = clazz.getDeclaredFields();for (Field declaredField : declaredFields) {Value valueAnnotation = declaredField.getAnnotation(Value.class);if (valueAnnotation!=null) {String value = valueAnnotation.value();String fieldName = declaredField.getName();String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);Method method = clazz.getMethod(methodName, declaredField.getType());//完成数据类型转换Object val = null;switch (declaredField.getType().getName()) {case "java.lang.Integer" -> val=Integer.parseInt(value);case "java.lang.String"-> val = value;case "java.lang.Float"-> Float.parseFloat(value);}method.invoke(object, val);}}//存入缓存ioc.put(beanName, object);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}}public Object getBean(String beanName) {return ioc.get(beanName);}public static void main(String[] args) {MyAnnotationConfigApplicationContext myAnnotationConfigApplicationContext = new MyAnnotationConfigApplicationContext("com.csdn.myspring");Person bean = (Person) myAnnotationConfigApplicationContext.getBean("b");System.out.println(bean.getName());}
}

4、@Component

package com.csdn.myspring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {String value() default "";
}

5、@Value

package com.csdn.myspring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {String value();
}

6、@Autowired

package com.csdn.myspring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

7、@Qualifier

package com.csdn.myspring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifier {String value();
}

@Qualifier是一个Spring框架的注解,用于标识一个Bean的特定实例。当有多个Bean实现了同一接口或类时,@Qualifier可以指定要使用的实例。

通常情况下,Spring框架根据类型来自动装配依赖,但如果有多个 Bean 与依赖的类型匹配,则会产生歧义。这时就需要使用 @Qualifier 来指定具体匹配的 Bean。

例如:

public interface Animal {// ...
}@Component
@Qualifier("cat")
public class Cat implements Animal {// ...
}@Component
@Qualifier("dog")
public class Dog implements Animal {// ...
}@Service
public class AnimalService {@Autowired@Qualifier("cat")private Animal animal;// ...
}

在这个例子中,AnimalService 类需要注入一个 Animal 接口的实例,但有两个实现类 Cat 和 Dog。使用 @Qualifier 标记 Cat 和 Dog 实例,然后在 AnimalService 中使用 @Autowired 和 @Qualifier("cat") 标记,就可以明确指定注入 Cat 实例了。

相关文章:

模拟Spring源码思想,手写源码,理解注解

1、BeanDefinition package com.csdn.myspring; import lombok.AllArgsConstructor; import lombok.Data; Data AllArgsConstructor public class BeanDefinition {private String beanName;private Class beanClass; }2、扫描包的工具类MyTools package com.csdn.myspring; im…...

各种LLM数据集包括SFT数据集

各种LLM数据集包括SFT数据集 数集介绍和 hf上的名字对话数据生成方法交通领域数据集SFT 的解释数集介绍和 hf上的名字 通用预训练数据集 SFT datasets SFT 数据集 50万条中文ChatGPT指令Belle数据集:BelleGroup/train_0.5M_CN 100万条中文ChatGPT指令Belle数据集:BelleGrou…...

Sleuth

Sleuth 一 引言 随着服务的越来越多&#xff0c;对调⽤链的分析会越来越复杂。它们之间的调⽤关系也许如下图&#xff1a; 问题&#xff1a; 1&#xff1a;微服务之间的调⽤错综复杂&#xff0c;⽤户发送的请求经历那些服务&#xff0c;调⽤链不清楚&#xff0c;没有⼀ 个⾃…...

新手必看!!附源码!!STM32通用定时器输出PWM

一、什么是PWM? PWM&#xff08;脉冲宽度调制&#xff09;是一种用于控制电子设备的技术。它通过调整信号的脉冲宽度来控制电压的平均值。PWM常用于调节电机速度、控制LED亮度、产生模拟信号等应用。 二、PWM的原理 PWM的基本原理是通过以一定频率产生的脉冲信号&#xff0…...

静态文件鉴权

​ 静态文件鉴权的解决方案 背景介绍 XX业务系统作为BXX业务系统的孪生姐妹系统&#xff0c;是对BXX受理业务的强力补充系统&#xff0c;他允许操作员拿着IPAD&#xff0c;和客户约定地点上门受理业务。 因一些业务的受理&#xff0c;按照最新的业务规章制度&#xff0c;需…...

计算机视觉与机器学习D1

计算机视觉简介 技术背景 了解人工智能方向、热点 目前人工智能的技术方向有&#xff1a; 1、计算机视觉——计算机视觉(CV)是指机器感知环境的能力&#xff1b;这一技术类别中的经典任务有图像形成、图像处理、图像提取和图像的三维推理。物体检测和人脸识别是其比较成功…...

layui(2.8.18)生成验证码

<!DOCTYPE html> <html> <head><meta charset"utf-8"><title>登入</title><meta name"renderer" content"webkit"><meta http-equiv"X-UA-Compatible" content"IEedge,chrome1&quo…...

MAX/MSP SDK学习05:A_GIMME方法

今天终于将A_GIMME方法部分的描述看懂了&#xff0c;上周因为太赶时间加上这文档很抽象一直没看懂。也就那么一回事&#xff0c;记录一下。 A_GIMME方法用于接收多个参数。 ①内置消息选择器传递多个参数时一定要使用A_GIMME&#xff1b; ②自定义消息选择器传递多个参数时建…...

LangChain: 类似 Flask/FastAPI 之于 Django,LangServe 就是「LangChain 自己的 FastAPI」

原文&#xff1a;LangChain: 类似 Flask/FastAPI 之于 Django&#xff0c;LangServe 就是「LangChain 自己的 FastAPI」 - 知乎 说明&#xff1a;LangServe代替 langchainserver 成为新的langchain 部署工具 官网资料&#xff1a;&#x1f99c;️&#x1f3d3; LangServe | &…...

mmdet全教程

官方给的文档一言难尽&#xff0c;网上的教程又没有从大纲到源码的完整解读&#xff0c;计划年后开个系列记录一下...

1992-2021年省市县经过矫正的夜间灯光数据(GNLD、VIIRS)

1992-2021年省市县经过矫正的夜间灯光数据&#xff08;GNLD、VIIRS&#xff09; 1、时间&#xff1a;1992-2021年3月&#xff0c;其中1992-2013年为年度数据&#xff0c;2013-2021年3月为月度数据 2、来源&#xff1a;DMSP、VIIRS 3、范围&#xff1a;分区域汇总&#xff1a…...

Guava的Retryer

Retryer类是Guava库中的一个重试工具类&#xff0c;它提供了一种在调用方法时自动重试的机制。Retryer类中的call()方法用于执行需要重试的方法&#xff0c;如果方法执行失败&#xff0c;则Retryer会根据配置的规则进行重试。Retryer类可以配置重试的次数、重试间隔时间、重试的…...

Docker实践笔记7:构建MySQL 8镜像

使用Docker构建MySQL 8镜像并运行容器 本教程将指导您使用Dockerfile构建和运行一个MySQL 8容器。让我们开始吧&#xff01; 步骤1&#xff1a;创建Dockerfile 在您的项目根目录下创建一个名为Dockerfile的文件。以下是Dockerfile的示例内容&#xff1a; # 基于最新的MySQL…...

# 学习 Prolog 和 离散逻辑的16个等价公式:一趟有趣的逻辑之旅

Prolog 的语法很奇怪,需要一些时间来适应,所以我花了点时间,想用Prolot来学习和验证离散逻辑的16组等价公式。 1. 双重否定律 (Double Negation Law) A ⇔A 首先&#xff0c;我们来看看双重否定律。在 Prolog 中&#xff0c;我们可以这样验证它&#xff1a; fun1(A,Z):-memb…...

Win11+Modelsim SE-64 10.6d搭建UVM环境

1、添加源文件及tb文件 在目录下建立文件夹&#xff0c;将DUT和Testbench添加进去&#xff0c;文件夹内容如下所示&#xff1a; 2、以《UVM实战》中的例子做简单的示例&#xff1a; 2.1 设计文件 &#xff1a;dut.sv 功能很简单&#xff0c;即将接受到的数据原封不动发送出去…...

LeetCode(32)串联所有单词的子串【滑动窗口】【困难】(含图解)

目录 1.题目2.答案3.提交结果截图4.图解 链接&#xff1a; 串联所有单词的子串 1.题目 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 w…...

【Delphi】使用TWebBrowser执行JavaScript命令传入JSON参数执行出错解决方案

目录 一、问题背景&#xff1a; 二、实际示例&#xff1a; 三、解决方案&#xff1a; 1. Delphi 代码&#xff1a; 2. javaScript代码&#xff1a; 一、问题背景&#xff1a; 在用Delphi开发程序&#xff0c;无论是移动端还是PC端&#xff0c;都可以很方便的使用TWebBrows…...

04 if进阶

elif 否则如果 如果条件没有满足 会继续进入“否则如果”里面判断 只要满足一个条件 条件判断立即终止 chinese 100 if chinese 100:print("我们去迪士尼玩")elif chinese > 90:print("我们去朱雀森林公园")else:print("回家写作业")if n…...

2023全球数字贸易创新大赛9-12

目录 回答评委提问:先说痛点-再说怎样解决 食品安全溯源是否全流程 星火• 链网...

vue3的两个提示[Vue warn]: 关于组件渲染和函数外部使用

1. [Vue warn]: inject() can only be used inside setup() or functional components. 这个消息是提示我们&#xff0c;需要将引入的方法作为一个变量使用。以vue-store为例&#xff0c;如果我们按照如下的方式使用&#xff1a; import UseUserStore from ../../store/module…...

别再只问GPU是否可用了!PyTorch中torch.cuda的5个隐藏实用技巧(含代码示例)

解锁PyTorch GPU潜能的5个高阶技巧&#xff1a;从基础检测到资源掌控 当你第一次在PyTorch中成功运行torch.cuda.is_available()并看到返回True时&#xff0c;那种喜悦就像拿到了通往深度学习加速世界的门票。但真正的高手知道&#xff0c;这只是GPU利用率的冰山一角。本文将带…...

从零到可运行:手把手在Ubuntu 20.04上为YOLOv5搭建TensorRT加速环境(含模型转换实战)

从零到可运行&#xff1a;手把手在Ubuntu 20.04上为YOLOv5搭建TensorRT加速环境&#xff08;含模型转换实战&#xff09; 在计算机视觉领域&#xff0c;YOLOv5凭借其出色的实时检测性能成为工业界的热门选择。但当我们将训练好的模型部署到实际生产环境时&#xff0c;往往会面临…...

终极指南:如何为Amlogic电视盒子刷入Armbian系统并解决网络兼容性问题

终极指南&#xff1a;如何为Amlogic电视盒子刷入Armbian系统并解决网络兼容性问题 【免费下载链接】amlogic-s9xxx-armbian Supports running Armbian on Amlogic, Allwinner, and Rockchip devices. Support a311d, s922x, s905x3, s905x2, s912, s905d, s905x, s905w, s905, …...

AI编程新范式:用cursor-rules实现工程化提示词驱动开发

1. 项目概述与核心价值如果你和我一样&#xff0c;长期在软件开发的一线摸爬滚打&#xff0c;那你肯定对“效率”和“质量”这两个词有着近乎偏执的追求。我们总是在寻找那个能让我们写代码更快、更准、更省心的“神器”。最近&#xff0c;我在一个名为cursor-rules的开源项目里…...

鸣潮智能剧情助手:5分钟实现后台自动跳过与多账号管理

鸣潮智能剧情助手&#xff1a;5分钟实现后台自动跳过与多账号管理 【免费下载链接】better-wuthering-waves &#x1f30a;更好的鸣潮 - 后台自动剧情 项目地址: https://gitcode.com/gh_mirrors/be/better-wuthering-waves 厌倦了《鸣潮》中重复冗长的剧情对话&#xf…...

AISMM模型落地不是咨询项目,而是组织能力手术:一位CTO亲述如何用90天重构AI治理中枢

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;AISMM模型在企业落地实践指南 AISMM&#xff08;AI-Driven Service Maturity Model&#xff09;是一种面向AI服务化演进的成熟度评估与实施框架&#xff0c;强调从数据治理、模型开发、服务编排到持续运…...

Gitee统一SCA解决方案:重新定义开源组件安全治理范式

在数字化转型浪潮席卷全球的当下&#xff0c;开源组件已成为现代软件开发不可或缺的基石。然而&#xff0c;伴随开源技术广泛应用而来的安全风险正以惊人速度增长&#xff0c;软件供应链攻击事件频发&#xff0c;使得企业面临前所未有的安全挑战。作为国内领先的代码托管平台&a…...

专业硬件信息保护工具深度解析:5步实现设备隐私防护

专业硬件信息保护工具深度解析&#xff1a;5步实现设备隐私防护 【免费下载链接】EASY-HWID-SPOOFER 基于内核模式的硬件信息欺骗工具 项目地址: https://gitcode.com/gh_mirrors/ea/EASY-HWID-SPOOFER EASY-HWID-SPOOFER是一款基于内核模式的硬件信息保护工具&#xff…...

文本到视频生成技术的多维度评估体系与实践

1. 项目背景与核心挑战文本到视频生成技术&#xff08;Text-to-Video Generation&#xff09;正在重塑内容创作领域。这项技术允许用户通过自然语言描述直接生成动态视频内容&#xff0c;其应用场景涵盖影视制作、广告设计、教育培训等多个领域。然而在实际应用中&#xff0c;我…...

3步彻底解决魔兽地图版本兼容性问题:w3x2lni专业指南

3步彻底解决魔兽地图版本兼容性问题&#xff1a;w3x2lni专业指南 【免费下载链接】w3x2lni 魔兽地图格式转换工具 项目地址: https://gitcode.com/gh_mirrors/w3/w3x2lni 你是否曾因魔兽争霸III版本更新而让精心制作的地图无法运行&#xff1f;w3x2lni正是解决这一痛点的…...