【Spring】我抄袭了Spring,手写一套MySpring框架。。。

这篇博客实现了一个简单版本的Spring,主要包括Spring的Ioc和Aop功能

文章目录

  • 这篇博客实现了一个简单版本的Spring,主要包括Spring的Ioc和Aop功能
    • 🚀@ComponentScan注解
    • ✈️@Component注解
    • 🚁在spring中ioc容器的类是ApplicationContext
    • 🚂测试类
    • 🚊MySpringConfig类,统一的配置类
    • 🚞OrderService类,一个普通的bean
      • 🚲来测试一下功能
    • 🚡@Scope注解
    • 🚟BeanDefinition 类
      • 🚠要实现我们的@scope注解,我们需要改造一下我们的代码
      • 🚜然后我们从beanDefinitionMap中实例化bean
      • 🚙我们来看一下效果
    • 🚘@Autowired注解
    • 🚗UserService类,orderservice注入该类
      • 🚗要使@Autowired注解生效,将bean实例化到一级缓存中方法需要改造一下
    • 🚕BeanPostProcessor接口
    • 🚖添加自己的BeanPostProcessor
    • 🚛Aop

🚀@ComponentScan注解

ComponentScan做的事情就是告诉Spring从哪里找到bean

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {

	String[] value() default {};

}

✈️@Component注解

@Component是spring中的一个注解,它的作用就是实现bean的注入

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

	String value() default "";


}

🚁在spring中ioc容器的类是ApplicationContext

所以我们需要创建一个ApplicationContext,有参构造传入config的class

public class ApplicationContext {

    public ApplicationContext(Class configClass) {
    
    }
    
}

存放bean的map

public class ApplicationContext {

 	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 
    public ApplicationContext(Class configClass) {
    
    }
    
}

拿到ComponentScan的值

public class ApplicationContext {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);


    public ApplicationContext(Class configClass) {
        //查看是否有ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String[] paths = componentScanAnnotation.value();
           
        }
    }
}

拿到该路径下所有的class文件

public class ApplicationContext {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);


    public ApplicationContext(Class configClass) {
        //查看是否有ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String[] paths = componentScanAnnotation.value();
            for (String path : paths) {

                //拿到包路径
                ClassLoader classLoader = ApplicationContext.class.getClassLoader();
                URL resource = classLoader.getResource(path.replace(".", "/"));
                //拿到该路径下所有的class文件
                File file = new File(resource.getFile());
                if (file.isDirectory()) {
                    File[] files = file.listFiles();
                    for (File f : files) {
                     
                    }
                }
            }
        }
    }
}

注册有Component注解的bean

public class ApplicationContext {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);


    public ApplicationContext(Class configClass) {
        //查看是否有ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String[] paths = componentScanAnnotation.value();
            for (String path : paths) {

                //拿到包路径
                ClassLoader classLoader = ApplicationContext.class.getClassLoader();
                URL resource = classLoader.getResource(path.replace(".", "/"));
                //拿到该路径下所有的class文件
                File file = new File(resource.getFile());
                if (file.isDirectory()) {
                    File[] files = file.listFiles();
                    for (File f : files) {
                        try {
                            String filePath = f.getPath();
                            //拿到com.masiyi.service.MySpringConfig
                            String sub = filePath.substring(filePath.indexOf("com"), filePath.indexOf(".class"));
                            String classes = sub.replace("\\", ".");
                            Class<?> aClass = classLoader.loadClass(classes);
                            //注册有Component注解的bean
                            if (aClass.isAnnotationPresent(Component.class)) {
                                Object bean = aClass.getDeclaredConstructor().newInstance();
                                Component component = aClass.getAnnotation(Component.class);
                                String beanName = component.value();
                                if ("".equals(beanName) || beanName == null) {
                                    singletonObjects.put(f.getName().split("\\.")[0], bean);
                                } else {
                                    singletonObjects.put(beanName, bean);
                                }
                            }
                        } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

🚂测试类

现在我们最基础的spring的ioc已经基本实现了,我们新建一个测试类来测试

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ApplicationContext(MySpringConfig.class);

    }
}

🚊MySpringConfig类,统一的配置类

@ComponentScan("com.masiyi.service")
public class MySpringConfig {

}

🚞OrderService类,一个普通的bean

@Component
public class OrderService {
}

🚲来测试一下功能

拿到包路径

在这里插入图片描述

拿到该路径下所有的class文件

在这里插入图片描述

注册有Component注解的bean

在这里插入图片描述

注册进ioc

在这里插入图片描述

getBean方法

  public Object getBean(String beanName) {
        return this.singletonObjects.get(beanName);
    }

在这里插入图片描述

🚡@Scope注解

@Scope注解是 Spring IOC 容器中的一个作用域

🚟BeanDefinition 类

BeanDefinition 是定义 Bean 的配置元信息接口,可以理解为创建bean过程中的一个中间类,扩展bean,存储更多的信息

public class BeanDefinition {
    private String scope;
    private Class aClass;

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public Class getaClass() {
        return aClass;
    }

    public void setaClass(Class aClass) {
        this.aClass = aClass;
    }
}

🚠要实现我们的@scope注解,我们需要改造一下我们的代码

把createBean方法抽离出来

  private void createBean(String beanName,Class<?> aClass){
        //注册有Component注解的bean
        if (aClass.isAnnotationPresent(Component.class)) {

            Component component = aClass.getAnnotation(Component.class);
            BeanDefinition beanDefinition = new BeanDefinition();
            if (aClass.isAnnotationPresent(Scope.class)) {
                Scope scope = aClass.getAnnotation(Scope.class);
                beanDefinition.setScope(scope.value());
            } else {
                beanDefinition.setScope("singleton");
            }
            beanDefinition.setaClass(aClass);

            String value = component.value();
            if ("".equals(value)) {
                beanDefinitionMap.put(beanName, beanDefinition);
            } else {
                beanDefinitionMap.put(value, beanDefinition);
            }
        }
    }

扫描ComponentScan注解的方法体改一下

🚜然后我们从beanDefinitionMap中实例化bean


        //将bean实例化到一级缓存中
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //单例
            if ("singleton".equals(beanDefinition.getScope())) {
                try {
                    Object bean = beanDefinition.getaClass().getDeclaredConstructor().newInstance();
                    singletonObjects.put(beanName, bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

getBean方法也需要改造

public Object getBean(String beanName) {
        BeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new NullPointerException();
        }
        if ("singleton".equals(beanDefinition.getScope())) {
            //如果是单例,直接返回缓存里的bean
            return this.singletonObjects.get(beanName);
        } else {
            try {
                //如果是多例,直接返回新的bean
                return beanDefinition.getaClass().getDeclaredConstructor().newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

🚙我们来看一下效果

在这里插入图片描述

这是没有加scope注解

在这里插入图片描述
返回的bean都是一个对象

我们给bean加上scope注解

在这里插入图片描述
返回来的bean每个都不一样

在这里插入图片描述

🚘@Autowired注解

spring中实现依赖注入的注解

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {

}

🚗UserService类,orderservice注入该类

@Component("userService")
public class UserService {
}

@Component
public class OrderService {
    @Autowired
    private UserService userService;


    public UserService getUserService() {
        return userService;
    }
}

🚗要使@Autowired注解生效,将bean实例化到一级缓存中方法需要改造一下

在这里插入图片描述

新增populateBean方法,用来初始bean


    private void populateBean(Object bean, Class aClass) {
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.isAnnotationPresent(Autowired.class)) {
                declaredField.setAccessible(true);
                try {
                    declaredField.set(bean, getBean(declaredField.getName()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

getBean方法也需要改造一下

在这里插入图片描述

这样我们的orderservice里面的userservice就有值了

在这里插入图片描述

🚕BeanPostProcessor接口

该接口在显示调用初始化方法的前后添加我们自己的逻辑

public interface BeanPostProcessor {
    /**
     * 之前
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    /**
     * 之后
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

我们创建存储BeanPostProcessor的list

在这里插入图片描述

在扫描的时候添加BeanPostProcessor

在这里插入图片描述

🚖添加自己的BeanPostProcessor

@Component
public class OrderPostProcessor implements BeanPostProcessor {
    /**
     * 之前
     *
     * @param bean
     * @param beanName
     * @return
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println(beanName+"执行前");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    /**
     * 之后
     *
     * @param bean
     * @param beanName
     * @return
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println(beanName+"执行后");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

实例化的时候执行BeanPostProcessor逻辑

在这里插入图片描述

运行结果

在这里插入图片描述

🚛Aop

jdk的动态代理是基于接口生成的代理对象

public interface OrderInterface {
    void test();
}

在这里插入图片描述

在OrderPostProcessor类中加以改造

在这里插入图片描述

这样我们就可以动态代理切入我们的orderservice类

在这里插入图片描述
在这里插入图片描述
以上就是全部内容

实现了以下

  • 🚀@ComponentScan注解
  • ✈️@Component注解
  • 🚁ApplicationContext类
  • 🚡@Scope注解
  • 🚟BeanDefinition 类
  • 🚘@Autowired注解
  • 🚕BeanPostProcessor接口
  • 🚛Aop
    内容,完成了一个超级简单且基础的spring源码

项目源码

博客码了两天,创作不易,多多点赞

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

来到CSDN的一些感想

之所以会写下今天这篇博客&#xff0c;是因为心中实在是有很多话想说&#xff01;&#xff01;&#xff01; 认识我的人应该都知道&#xff0c;我是才来CSDN不久的&#xff0c;也可以很清楚地看见我的码龄&#xff0c;直到今天&#xff1a;清清楚楚地写着&#xff1a;134天&…

狄拉克符号系统

狄拉克符号系统&#xff1a;狄拉克构造了一个抽象的、一般矢量--态矢和一整套狄拉克符号以描述量子力学体系的状态一般狄拉克符号任何力学量的完全集的本征函数系作为基矢构成希尔伯特空间&#xff0c;微观体系的状态波函数作为该空间的一个态矢&#xff0c;有且仅有。态矢在所…

手把手教你基于HTML、CSS搭建我的相册(上)

The sand accumulates to form a pagoda写在前面HTML是什么&#xff1f;CSS是什么&#xff1f;demo搭建写在最后写在前面 其实有过一些粉丝咨询前端该从什么开始学&#xff0c;那当然是我们的前端基础三件套开始学起&#xff0c;HTML、CSS、javaScript&#xff0c;前端的大部分…

Qt学习_11_构建内嵌子界面与独立子界面的框架

0 前言 对于较大的Qt项目而言&#xff0c;弹出的独立子界面 与 根据菜单在主窗口内切换的内嵌子界面是我们所必须面对的问题。那么在项目框架对这两部分内容应该如何布局&#xff0c;才能让项目更清爽&#xff0c;更规整。是本文着重讨论的内容。下图给出我们的最终设计框架。…

html+css 实现 熊猫样式

效果 html代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible"…

【Docker】镜像的原理定制化镜像

文章目录镜像是什么UnionFS&#xff08;联合文件系统&#xff09;Docker镜像加载原理制作本地镜像 docker commit -m"提交的描述信息" -a"作者" 容器ID 要创建的目标镜像名:[标签名]案例演示ubuntu安装vim本地镜像发布到阿里云本地镜像发布到阿里云流程将本…

【AI大比拼】文心一言 VS ChatGPT-4

摘要&#xff1a;本文将对比分析两款知名的 AI 对话引擎&#xff1a;文心一言和 OpenAI 的 ChatGPT&#xff0c;通过实际案例让大家对这两款对话引擎有更深入的了解&#xff0c;以便大家选择合适的 AI 对话引擎。 亲爱的 CSDN 朋友们&#xff0c;大家好&#xff01;近年来&…

面部表情识别3:Android实现表情识别(含源码,可实时检测)

面部表情识别3&#xff1a;Android实现表情识别(含源码&#xff0c;可实时检测) 目录 面部表情识别3&#xff1a;Android实现表情识别(含源码&#xff0c;可实时检测) 1.面部表情识别方法 2.人脸检测方法 3.面部表情识别模型训练 4.面部表情识别模型Android部署 &#x…

YOLOv8 多目标跟踪

文章大纲 简介环境搭建代码样例跟踪原理代码分析原始老版实现新版本封装代码实现追踪与计数奇奇怪怪错误汇总lap 安装过程报错推理过程报错参考文献与学习路径简介 使用yolov8 做多目标跟踪 文档地址: https://docs.ultralytics.com/modes/track/https://github.com/ultralyt…

【Unity3D】Unity3D中在创建完项目后自动创建文件夹列表

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 随着项目开发的体量增大&#xff0c;要导入大量的素材、UI、模…

ABC294(A-E)

AtCoder Beginner Contest 294 Contest Duration: 2023-03-19(Sun) 20:00 - 21:40 (local time) (100 minutes) A Filter 按顺序输出偶数 int n;cin>>n;int a[n];fer(i,0,n)cin>>a[i];fer(i,0,n){if(!(a[i]&1))cout<<a[i]<<" ";}B ASCI…

ARM uboot 的移植5 -从 uboot 官方标准uboot 开始移植

一、环境变量的移植 1、iNand分区表检查 - env 究竟应该放在哪 (1) 测试环境变量是否可以保存。通过开机 set 设置环境变量,然后 save,然后关机后重启来测试环境变量的保存是否成功。 (2) 我们的环境变量究竟保存到哪里去了?这个就要去分析代码中的分区表。 (3) 环境变量…

第十四届蓝桥杯三月真题刷题训练——第 16 天

目录 第 1 题&#xff1a;英文字母 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约定 运行限制 代码&#xff1a; 第 2 题&#xff1a;单词分析 题目描述 输入描述 输出描述 输入输出样例 运行限制 数组代码&…

基于STM32的ADC采样及各式滤波实现(HAL库,含VOFA+教程)

前言&#xff1a;本文为手把手教学ADC采样及各式滤波算法的教程&#xff0c;本教程的MCU采用STM32F103ZET6。以HAL库的ADC采样函数为基础进行教学&#xff0c;通过各式常见滤波的实验结果进行分析对比&#xff0c;搭配VOFA工具直观的展示滤波效果。ADC与滤波算法都是嵌入式较为…

最低仅需一张入门级显卡便可运行扩散模型AI作画——Stable Diffusion Webui试玩体验 文本生成图像扩散模型本机推理

最近在网上发现了一款训练好了的Stable Diffusion 友好的Webui&#xff0c;具有完全免费、离线运行、解压即用、超简单配置、全部汉化、效果惊人的Stable Diffusion Webui项目&#xff0c;在此分享给大家。 在此首先感谢&#xff1a; 大佬原始的webui项目&#xff1a;https:/…

4.网络爬虫—Post请求(实战演示)

网络爬虫—Post请求实战演示POST请求GET请求POST请求和GET请求的区别获取二进制数据爬[百度官网](https://www.baidu.com/)logo实战发送post请求百度翻译实战使用session发送请求模拟登录17k小说网常见问题前言&#xff1a; &#x1f4dd;​&#x1f4dd;​此专栏文章是专门针对…

嵌入式硬件电路设计的基本技巧

目录 1 分模块 2 标注关键参数 3 电阻/电容/电感/磁珠的注释 4 可维修性 5 BOM表归一化 6 电源和地的符号 7 测试点 8 网络标号 9 容错性/兼容性 10 NC、NF 11 版本变更 12 悬空引脚 13 可扩展性 14 防呆 15 信号的流向 16 PCB走线建议 17 不使用\表示取反 不…

springboot车辆充电桩

sprinboot车辆充电桩演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;ecli…

从零到Offer -- List的那些事

ArrayList ​ 作为日常最常见的collection对象&#xff0c;相信大家对于ArrayList都不陌生。但是ArrayList的实现你是否又了解呢&#xff1f;开门见山&#xff0c;ArrayList的最底层实现其实就是一个数组&#xff1a; transient Object[] elementData;public ArrayList() {th…

springboot+vue驾校管理系统 idea科目一四预约考试,练车

加大了对从事道路运输经营活动驾驶员的培训管理力度&#xff0c;但在实际的管理过程中&#xff0c;仍然存在以下问题&#xff1a;(1)管理部门内部人员在实际管理过程中存在人情管理&#xff0c;不进行培训、考试直接进行发证。(2)从业驾驶员培训机构不能严格执行管理部门的大纲…
最新文章