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

手写Spring容器核心原理

一、Spring容器基础架构

/*** Zhouyu-Spring核心容器类* 职责:加载配置、管理Bean定义、创建和管理Bean实例*/
public class ZhouyuApplicationContext {// 存储配置类的Class对象,用于获取扫描路径等配置信息private Class configClass;// Bean定义映射表:key=Bean名称, value=Bean元数据(类型、作用域等)private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();// 单例对象池:缓存单例Bean实例(key=Bean名称)private ConcurrentHashMap<String, Object> singletonObject = new ConcurrentHashMap<>();/*** 容器构造器* @param configClass Spring配置类的Class对象*/public ZhouyuApplicationContext(Class configClass) {this.configClass = configClass;// 初始化容器:扫描包路径、注册Bean定义、初始化单例Beaninitialize();}/*** 核心方法:根据Bean名称获取Bean实例* @param beanName 要获取的Bean名称* @return Bean实例对象*/public Object getBean(String beanName) {// 具体实现将在第五部分完成return null;}
}

创建容器时传入配置类

public class Test {public static void main(String[] args) {// 创建Spring容器实例,传入配置类ZhouyuApplicationContext context = new ZhouyuApplicationContext(AppConfig.class);// 从容器中获取名为"userService"的Bean实例UserService userService = (UserService) context.getBean("userService");}
}

二、核心注解实现

1. 组件扫描注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 组件扫描注解:标识要扫描的包路径* 只能标注在类上,运行时保留*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {/*** 指定要扫描的包路径* @return 包路径字符串(如"com.zhouyu.service")*/String value() default "";
}

2. 组件标识注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 组件标识注解:标记需要被容器管理的类* 只能标注在类上,运行时保留*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {/*** 指定Bean在容器中的名称* @return Bean名称(如"userService")*/String value() default "";
}

3. 单例多利注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {/*** 指定Bean是单例还是多礼* @return (如"singleton"或"prototype")*/String value() default "";
}

三、配置类与Bean定义

配置类示例
/*** Spring配置类示例* 使用@ComponentScan指定扫描包路径*/
@ComponentScan("com.zhouyu.service") // 扫描com.zhouyu.service包及其子包
public class AppConfig {// 配置类可以包含其他配置信息
}

Bean定义类
/*** Bean定义类:封装Bean的元数据信息*/
public class BeanDefinition {// Bean的Class类型(如UserService.class)private Class type;// Bean的作用域(singleton/prototype)private String scope;// Setter和Getter方法public Class getType() {return type;}public void setType(Class type) {this.type = type;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}
}

四、容器初始化流程

1. 扫描路径处理
/*** 容器初始化方法* 1. 解析配置类的@ComponentScan注解* 2. 扫描指定包路径下的所有类文件* 3. 创建所有单例Bean*/
private void initialize() {// 检查配置类是否有ComponentScan注解if (configClass.isAnnotationPresent(ComponentScan.class)) {// 获取注解实例ComponentScan scan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);// 将包路径转换为文件系统路径(com.zhouyu.service -> com/zhouyu/service)String path = scan.value().replace(".", "/");// 获取类加载器ClassLoader classLoader = getClass().getClassLoader();// 获取资源在类路径中的位置URL resource = classLoader.getResource(path);// 将URL转为文件对象File dir = new File(resource.getFile());// 确保是目录if (dir.isDirectory()) {// 遍历目录下所有文件for (File file : dir.listFiles()) {// 处理每个文件(类文件)processClassFile(file, classLoader);}}}// 初始化所有单例Bean(容器启动时创建)createSingletonBeans();
}

2. 类文件处理逻辑
/*** 处理单个类文件* @param file 类文件对象* @param classLoader 类加载器*/
private void processClassFile(File file, ClassLoader classLoader) {String fileName = file.getAbsolutePath();// 只处理.class文件if (fileName.endsWith(".class")) {// 从绝对路径中提取完整类名(com\zhouyu\service\UserService -> com.zhouyu.service.UserService)String className = fileName.substring(fileName.indexOf("com"),       // 从"com"开始fileName.indexOf(".class")      // 到".class"结束).replace("\\", ".");              // 替换路径分隔符try {// 加载类对象Class<?> clazz = classLoader.loadClass(className);// 检查是否有@Component注解if (clazz.isAnnotationPresent(Component.class)) {// 注册Bean定义到容器registerBeanDefinition(clazz);}} catch (Exception e) {e.printStackTrace();}}
}

3. Bean定义注册
/*** 注册Bean定义到容器* @param clazz 要注册的Class对象*/
private void registerBeanDefinition(Class<?> clazz) {// 获取@Component注解配置Component component = clazz.getAnnotation(Component.class);String beanName = component.value();// 创建Bean定义对象BeanDefinition definition = new BeanDefinition();definition.setType(clazz); // 设置Bean类型// 检查是否有@Scope注解if (clazz.isAnnotationPresent(Scope.class)) {// 获取作用域配置Scope scope = clazz.getAnnotation(Scope.class);definition.setScope(scope.value());} else {// 默认单例模式definition.setScope("singleton");}// 将Bean定义存入映射表beanDefinitionMap.put(beanName, definition);
}

五、Bean创建与管理

1. 单例Bean预创建
/*** 初始化所有单例Bean(在容器启动时创建)*/
private void createSingletonBeans() {// 遍历所有Bean定义for (String beanName : beanDefinitionMap.keySet()) {BeanDefinition definition = beanDefinitionMap.get(beanName);// 只处理单例Beanif ("singleton".equals(definition.getScope())) {// 创建Bean实例Object bean = createBean(beanName, definition);// 存入单例对象池singletonObject.put(beanName, bean);}}
}

2. Bean实例化方法
/*** 创建Bean实例* @param beanName Bean名称* @param definition Bean定义* @return 创建的Bean实例*/
private Object createBean(String beanName, BeanDefinition definition) {Class clazz = definition.getType();try {// 通过默认构造器创建实例(反射机制)return clazz.getConstructor().newInstance();} catch (Exception e) {// 封装创建异常throw new RuntimeException("创建Bean失败: " + beanName, e);}
}

3. getBean实现
/*** 获取Bean实例的核心方法* @param beanName 要获取的Bean名称* @return Bean实例* @throws NullPointerException 如果找不到Bean定义*/
public Object getBean(String beanName) {// 从Bean定义映射表获取元数据BeanDefinition definition = beanDefinitionMap.get(beanName);// 检查Bean定义是否存在if (definition == null) {throw new NullPointerException("未定义的Bean: " + beanName);}// 获取Bean的作用域配置String scope = definition.getScope();// 根据作用域类型返回Bean实例if ("singleton".equals(scope)) {// 单例模式:从单例池获取Object bean = singletonObject.get(beanName);// 双重检查:如果还未创建则创建并缓存if (bean == null) {bean = createBean(beanName, definition);singletonObject.put(beanName, bean);}return bean;} else {// 原型模式:每次创建新实例return createBean(beanName, definition);}
}

http://www.dtcms.com/a/336945.html

相关文章:

  • 加密资产投资的六种策略:稳定币合规后的 Web3 投资和 RWA
  • 杂记 05
  • ARM 架构简明教程学习笔记
  • 微信原生小程序的一次gulp构建
  • DevExtreme Angular UI控件更新:引入全新严格类型配置组件
  • Kafka的ISR、OSR、AR详解
  • Rust学习笔记(六)|Rust 中的常用集合(Vector、String、HashMap)
  • Linux网络服务(一)——计算机网络参考模型与子网划分
  • 计算机网络:2、TCP和UDP
  • Golang context
  • CentOS 7 LAMP快速部署WordPress指南
  • 云原生Ansible渗透场景(⾃动化的运维⼯具)
  • Ansible企业及实战
  • OVS:除了Geneve和VXLAN,还有哪些虚拟化网络协议?
  • 云计算:企业数字化转型的核心引擎
  • 传统方式部署(RuoYi-Cloud)微服务
  • 一套GoldenGate → Kafka → Flink → MySQL 的端到端增量同步方案
  • 云计算学习100天-第17天
  • Linux学习-(进程间,线程间通信)
  • nuScence数据集
  • 计算机视觉 图像处理 在两张二值图中检测线条交集点的高效方法 适合工程图纸比对、生物神经元网络分析和文档特征提取等场景 ,
  • 20. 云计算-Service MeshServerless
  • 谷粒商城项目-P3简介-分布式基础概念
  • CloudBase AI ToolKit + VSCode Copilot:打造高效智能云端开发新体验
  • 【运维进阶】LNMP + WordPress 自动化部署实验
  • CMakeLists.txt 学习笔记
  • MariaDB/MySQL 客户端工具与服务端配置精要指南
  • C++---有符号和无符号整数的位移操作
  • 云原生俱乐部-mysql知识点归纳(1)
  • 《亚矩阵云手机重构出租接单:KVM 虚拟化与边缘计算驱动的设备替代技术路径》