手写模拟Spring底层原理-简易实现版

通过手写模拟Spring

  • 了解Spring的底层源码启动过程
  • 了解BeanDefinition、BeanPostProcessor的概念
  • 了解Spring解析配置类等底层源码工作流程
  • 了解依赖注入,Aware回调等底层源码工作流程
  • 了解Spring AOP的底层源码工作流程

这里实现一个简化版的 Spring 框架的核心功能,模拟应用程序上下文(ApplicationContext)的创建、bean 的定义、依赖注入、作用域管理和后置处理等过程。

实际的 Spring 框架在此基础上还有更多功能和复杂性,这里只提供一个基础的理解。

核心功能:

  • BubbleApplicationContext 是主要的应用程序上下文类,负责管理 bean 的定义和实例化。
  • BeanDefinition 用于封装 bean 的定义,包括类型和作用域等信息。
  • BeanPostProcessor 接口定义了在 bean 创建过程中的后置处理方法。

数据结构:

  • beanDefinitionMap 存储了 bean 的定义信息,以 bean 名称为键。
  • singletonObjects 保存了单例 bean 的实例,以 bean 名称为键。
  • beanPostProcessorList 包含实现了 BeanPostProcessor 接口的后置处理器。

初始化流程:

  • 构造方法扫描配置类,初始化 beanDefinitionMapbeanPostProcessorList
  • 对于单例 bean,遍历 beanDefinitionMap,创建和初始化实例,存入 singletonObjects

bean 创建和初始化:

  • createBean 方法使用反射创建 bean 实例,包括依赖注入和后置处理逻辑。
  • 自动注入带有 Autowired 注解的字段。
  • 设置 bean 的名称,如果实现了 BeanNameAware 接口。
  • 执行前置后置处理器的逻辑。
  • 如果实现了 InitializingBean 接口,执行初始化逻辑。

获取 bean 实例:

  • getBeen 方法根据 bean 名称获取 bean 实例。
  • 对于单例,如果实例已存在,直接返回;否则创建并存入。
  • 对于原型,每次获取都创建新实例。

扫描和初始化:

  • scan 方法扫描配置类,初始化 bean。
  • 判断是否标注了 ComponentScan 注解,获取扫描路径。
  • 遍历类文件,解析 Component 注解,初始化 bean。

简易实现代码如下:

目录结构:

package com.spring;import java.beans.Introspector;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class BubbleApplicationContext {private Class configClass;// 存储 BeanDefinition 对象的映射,用于管理 bean 的定义信息private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();// 存储单例对象的映射,用于管理单例 bean 的实例private Map<String, Object> singletonObjects = new HashMap<>();// 存储 BeanPostProcessor 的列表,用于后置处理 bean,,,spring用的LinkListprivate List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();// 构造方法,在创建 ApplicationContext 时传入配置类public BubbleApplicationContext(Class configClass) {this.configClass = configClass;// 扫描配置类并初始化 beanDefinitionMap,,beanPostProcessorListscan(configClass);// 遍历 beanDefinitionMap,创建并初始化单例对象,并存入 singletonObjectsfor (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();if (beanDefinition.getScope().equals("singleton")) {Object bean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, bean);}}}// 创建 bean 对象的方法,包括依赖注入、后置处理等逻辑private Object createBean(String beanName, BeanDefinition beanDefinition) {Class clazz = beanDefinition.getType();//com.bubble.service.UserServiceObject instance = null;try {instance = clazz.getConstructor().newInstance(); // 使用反射创建实例for (Field field : clazz.getDeclaredFields()) {// 对带有 Autowired 注解的字段进行依赖注入if (field.isAnnotationPresent(Autowired.class)) {field.setAccessible(true);field.set(instance, getBeen(field.getName()));}}// 若实现了 BeanNameAware 接口,设置 bean 的名称if (instance instanceof BeanNameAware) {((BeanNameAware) instance).setBeanName(beanName);}// 执行 BeanPostProcessor 的前置处理逻辑for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}// 若实现了 InitializingBean 接口,执行初始化逻辑if (instance instanceof InitializingBean) {((InitializingBean)instance).afterPropertiesSet();}// 执行 BeanPostProcessor 的后置处理逻辑for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}} 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);}return instance;}// 获取 bean 对象的方法,支持单例和原型两种作用域public Object getBeen(String beanName) {// 如果beanDefinitionMap中不包含beanName,说明传入的bean是不存在的if (!beanDefinitionMap.containsKey(beanName)) {throw new NullPointerException();}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")) {Object singletonBean = singletonObjects.get(beanName);if (singletonBean == null) {singletonBean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, singletonBean);}return singletonBean;} else {// 原型(多例)Object prototypeBean = createBean(beanName, beanDefinition);return prototypeBean;}}/*** 扫描指定配置类,解析其中的 ComponentScan 注解,根据注解配置的扫描路径* 查找并解析带有 Component 注解的类,初始化对应的 BeanDefinition。** @param configClass 配置类,用于查找 ComponentScan 注解*/private void scan(Class configClass) {// 检查配置类是否标注了 ComponentScan 注解if(configClass.isAnnotationPresent(ComponentScan.class)) {// 获取 ComponentScan 注解实例ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);// 获取扫描路径,并将包名中的点替换为斜线,以便在类加载器中定位资源String path = componentScanAnnotation.value();path = path.replace(".","/");// com/bubble/service// 获取类加载器,用于加载类和资源ClassLoader classLoader = BubbleApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);// 根据扫描路径获取资源 URLFile file = new File(resource.getFile());// 将 URL 转换为文件对象,以便遍历目录和文件// 判断是否为目录,如果是目录则遍历其中的文件if(file.isDirectory()){for (File f : file.listFiles()) {// 获取文件的绝对路径String absolutePath = f.getAbsolutePath();//E:\Dev\Spring\bubble-spring\target\classes\com\bubble\service\UserService.class// 提取类路径部分,去除文件扩展名absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));//com\bubble\service\UserService// 将文件路径中的斜线替换为点,得到完整的类名absolutePath = absolutePath.replace("\\", ".");//com.bubble.service.UserServicetry {// 使用类加载器加载类Class<?> clazz = classLoader.loadClass(absolutePath);// 判断类是否标注了 Component 注解,表示为一个需要管理的 beanif (clazz.isAnnotationPresent(Component.class)) {// 如果类实现了 BeanPostProcessor 接口,将其实例化并加入 beanPostProcessorListif (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}// 获取 Component 注解实例Component componentAnnotation = clazz.getAnnotation(Component.class);// 获取 bean 的名称,如果未指定,则使用类名的首字母小写作为默认名称String beanName = componentAnnotation.value();if ("".equals(beanName)) {beanName = Introspector.decapitalize(clazz.getSimpleName());}// 创建并初始化 BeanDefinition 对象BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(clazz);// 判断类是否标注了 Scope 注解,设置 bean 的作用域if (clazz.isAnnotationPresent(Scope.class)) {Scope scopeAnnotation = clazz.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);} else {// 默认作用域为 singletonbeanDefinition.setScope("singleton");}// 将 BeanDefinition 添加到 beanDefinitionMap 中,以便后续使用beanDefinitionMap.put(beanName, beanDefinition);}} 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);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}}}}}
package com.spring;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.FIELD)
public @interface Autowired {
}
package com.spring;public class BeanDefinition {private Class type;private String scope;private boolean isLazy;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;}public boolean isLazy() {return isLazy;}public void setLazy(boolean lazy) {isLazy = lazy;}
}
public interface BeanNameAware {void setBeanName(String name);
}
public interface BeanPostProcessor {default Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}default Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}
}
package com.spring;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 {String value() default "";
}
package com.spring;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 {String value() default "";
}

public interface InitializingBean {void afterPropertiesSet();
}
package com.spring;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 {String value() default "";
}
package com.bubble.service;import com.spring.BeanPostProcessor;
import com.spring.Component;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//自定义 Bean 后置处理器,用于在 Bean 初始化之后,对特定的 Bean 进行切面逻辑的处理。
@Component
public class BubbleBeanPostProcessor implements BeanPostProcessor {//在 Bean 初始化之后,对特定的 Bean 进行切面逻辑处理。@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {// 判断是否是特定的 Bean,这里以 "userService" 为例if (beanName.equals("userService")) {// 创建动态代理对象,用于在原始方法调用前后添加切面逻辑Object proxyInstance = Proxy.newProxyInstance(BubbleBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 切面System.out.println("切面逻辑");return method.invoke(bean, args);}});// 返回代理对象,即添加了切面逻辑的 Bean 实例return proxyInstance;}//对于其他 Bean,保持原样返回,不添加切面逻辑return bean;}
}
package com.bubble.service;import com.spring.BeanPostProcessor;
import com.spring.Component;import java.lang.reflect.Field;//自定义 Bean 后置处理器,用于在 Bean 初始化之前,根据 BubbleValue 注解为特定的字段赋值。
@Component("userService")
public class BubbleValueBeanPostProcessor implements BeanPostProcessor {//在 Bean 初始化之前,根据 BubbleValue 注解为特定的字段赋值。@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {for (Field field : bean.getClass().getDeclaredFields()) {// 检查字段是否标注了 BubbleValue 注解if (field.isAnnotationPresent(BubbleValue.class)) {field.setAccessible(true);// 设置字段的访问权限,允许反射访问私有字段try {field.set(bean, field.getAnnotation(BubbleValue.class).value());} catch (IllegalAccessException e) {e.printStackTrace();}}}// beanreturn bean;}
}
package com.bubble.service;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.FIELD)
public @interface BubbleValue {String value() default "";
}

package com.bubble.service;import com.spring.Component;@Component
public class OrderService {public void test() {System.out.println("test->OrderService");}
}
public interface UserInterface {public void test();
}
package com.bubble.service;import com.spring.Autowired;
import com.spring.BeanNameAware;
import com.spring.Component;@Component("userService")
public class UserService implements UserInterface, BeanNameAware {@Autowiredprivate OrderService orderService;@BubbleValue("bubble")private String test;private String beanName;@Overridepublic void setBeanName(String name) {this.beanName = name;}//    public void test() {
//        System.out.println("test");
//    }@Overridepublic void test() {System.out.println(beanName);System.out.println(test);}
}
package com.bubble;import com.spring.ComponentScan;@ComponentScan("com.bubble.service")
public class AppConfig {
}

程序调用测试

public class Test {public static void main(String[] args) {//扫描-->创建单例bean BeanDefinition BeanPostPRocessBubbleApplicationContext applicationContext = new BubbleApplicationContext(AppConfig.class);//UserService userService = (UserService)applicationContext.getBeen("userService");UserInterface userService = (UserInterface) applicationContext.getBeen("userService");userService.test();}
}

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

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

相关文章

GraphRAG深入解析

GraphRAG深入解析 GraphRAG 深入解析概述索引查询 索引过程深入解析步骤 1&#xff1a;处理文本块步骤 2&#xff1a;图提取步骤 3&#xff1a;图增强步骤 4&#xff1a;社区总结步骤 5&#xff1a;文件处理步骤 6&#xff1a;网络可视化 查询过程深入解析本地搜索问题生成全局…

苹果安卓分发的秘密:如何选择正确的渠道(苹果安卓分发)

苹果安卓分发的重要性 随着移动互联网的普及&#xff0c;移动应用程序的开发和分发变得越来越重要。苹果安卓分发是移动应用程序开发者的首要任务之一&#xff0c;因为它直接关系到应用程序的推广和收益。 苹果安卓分发并不是一件简单的事情。开发者需要选择正确的渠道&#…

Pytorch使用教学5-视图view与reshape的区别

有同学后台留言问为什么view有时可对张量进行形变操作&#xff0c;有时就会报错&#xff1f;另外它和reshape功能好像一致&#xff0c;有什么区别呢&#xff1f;本文就带你了解PyTorch中视图的概念。 在PyTorch中对张量进行形变操作时&#xff0c;很多同学也会使用view方法&am…

监测Nginx访问日志状态码,并做相应动作

文章目录 引言I 监测 Nginx 访问日志情况,并做相应动作1.1 前提准备1.2 访问日志 502 情况,重启 bttomcat9服务1.3 其他案例:访问日志 502 情况,重启 php-fpm 服务II 将Shell 脚本check499.sh包装成systemd服务2.1 创建systemd服务2.2 配置service2.3 开机启动2.4 其他常用…

华为ICT大赛之ensp软件BGP原理与配置

BGP基础 1.用于不同自治系统AS(autonomous system)之间动态交换路由信息&#xff1b; BGP取代EGP(exterior gateway protocol)外部网关协议&#xff0c;BGP在其发布路由信息基础上可以进行路由优选&#xff0c;高效处理路由信息&#xff1b; AS:同一组织管理下&#xff0c;使…

RK3568平台(显示篇)显示系统基本概念

一.显示系统概述 linux内核中包含两类图形显示设备驱动框架&#xff1a; FB设备&#xff1a;Framebuffer图形显示框架;DRM&#xff1a;直接渲染管理器&#xff08;Direct Rendering Manager&#xff09;&#xff0c;是linux目前主流的图形显示框架&#xff1b; 在实际场景中…

打通“链上数据脉络” 欧科云链数字生态建设成果凸显

7月25日&#xff0c;据Coindesk报道&#xff0c;全球领先的区块链技术和服务提供商欧科云链宣布旗下OKLink浏览器与Polygon Labs正式达成合作&#xff0c;成为AggLayer首个区块链搜索引擎及Web3数据分析平台&#xff0c;将为开发者提供精简易用的链上数据访问和开发工具&#x…

MATLAB学习教程(一)

目录 1.常见函数基本运算 2.二维绘制: plot(​..) 3.三维绘制: plot3(​..) / mesh(​..) 4.绘图美化 标题及标签 绘图命令&#xff1a;color 绘图命令&#xff1a;Line 5.代码 1.常见函数基本运算 方根函数sqrt() 自然指数函数exp() 以10为底的对数函…

巴斯勒相机(Basler) ACE2 dart 系列说明和软件

巴斯勒相机(Basler) ACE2 dart 系列说明和软件

了解高防 IP

一、高防 IP 的基本概念 高防 IP 是指拥有强大防御能力的 IP 地址。它主要通过将攻击流量引流到高防机房进行清洗和过滤&#xff0c;再将正常的流量回注到源站&#xff0c;从而保障源站服务器的稳定运行。 二、高防 IP 的工作原理 当用户的服务器遭受 DDoS 攻击时&#xff0…

Ubuntu22.04手动安装fabric release-2.5版本

这个过程稍微有点复杂&#xff0c;但完整操作完成以后会对Fabric网络有更加深入的理解&#xff0c;方便后续自己手动搭建Fabric网络。这个过程需要手动逐个下载Fabric源代码、使用命令下载Fabric镜像和用Git下载例子程序。 Fabric源代码主要用途是用来编译cryptogen、configtx…

redis的使用场景

目录 1. 热点数据缓存 1.1 什么是缓存&#xff1f; 1.2 缓存的原理 1.3 什么样的数据适合放入缓存中 1.4 哪个组件可以作为缓存 1.5 java使用redis如何实现缓存功能 1.5.1 需要的依赖 1.5.2 配置文件 1.5.3 代码 1.5.4 发现 1.6 使用缓存注解完成缓存功能 2. 分布式锁…

【Python Web】Flask扩展开发指南

Flask是一个轻量级的Python Web框架&#xff0c;它提供了丰富的扩展库和工具&#xff0c;可以帮助开发者快速构建Web应用。本篇博客将介绍如何进行Flask扩展开发&#xff0c;包括扩展的创建、配置、使用等方面的内容。 目录 Flask扩展开发指南 一、Flask扩展简介 二、创建Fl…

原子操作类(持续更新,未完结)

目录 基本类型原子类数组类型原子类引用类型原子类对象的属性修改原子类原子操作增强类LongAdder 高性能原理说明LongAdder源码深度解析LongAdder小总结 相关文献 分组来给大家讲解相关原子类的常用api使用&#xff0c;不会全部都讲完&#xff0c;只是抽取几个比较经典的讲一下…

c++树(三)重心

目录 重心的基础概念 定义&#xff1a;使最大子树大小最小的点叫做树的重心 树的重心求解方式 例题&#xff1a; 重心的性质 性质1&#xff1a;重心点的最大子树大小不大于整棵树大小的一半。 性质1证明&#xff1a; 性质1的常用推导 推导1&#xff1a; 推导2&#x…

AI绘画SD中 ControlNet 组件 IP-Adapter 实现风格迁移,AI绘画垫图神器!

大家好&#xff0c;我是画画的小强 今天给大家介绍一下AI绘画SD中ControlNet 的 IP-Adapter 组件&#xff0c;该组件可以方便快捷的帮我们对图片的风格进行迁移&#xff0c;简而言之就是可以参考你放置的图片风格来生成其他图片。 它的效果和reference only有点类似&#xff…

了解网络是如何运作

“Web 的工作原理”提供了一个简化的视图,用于了解在计算机或手机上的 Web 浏览器中查看网页时发生的情况。 这个理论对于短期内编写 Web 代码来说并不是必需的,但不久之后,你就会真正开始从理解后台发生的事情中受益。 客户端和服务器 连接到 Internet 的计算机称为客户端和…

四、面向对象2(30小时精通C++和外挂实战)

四、面向对象2&#xff08;30小时精通C和外挂实战&#xff09; B-01-对象的内存B-02-构造函数B-04-成员变量的初始化B-05-析构函数B-06-内存管理B-07-类的声明和实现分离B-08-命名空间B-09-继承B-10-成员访问权限 B-01-对象的内存 在C中对象可以自由的放在3中地方&#xff0c;而…

【算法】插入排序 与 希尔排序 概念+图解+代码【Python C C++】

1.插入排序 1.1概念 插入排序(InsertionSort)&#xff0c;一般也被称为直接插入排序。 对于少量元素的排序&#xff0c;它是一个有效的算法。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个元素插入到已经排好序的有序表中&#xff0c;从而构造出一个新的…

mathtype7.4永久激活码(mathtype7永久注册码网盘下载)

大家好&#xff0c;我是你们的数学小能手&#xff01;今天我要安利一款超实用的工具——MathType&#xff0c;让你在数学的世界里游刃有余&#xff0c;轻松搞定各种公式和计算。准备好被种草了吗&#xff1f;跟我一起来瞧瞧吧&#xff01; MathType是理科生专用的必备工具&…