手写一个简单版的Spring

news2024/11/15 11:08:37

1. 创建一个工程及初始化

  1. 创建Java工程
    在这里插入图片描述

  2. 创建对应的包
    在这里插入图片描述
    config:为配置类包
    service:定义的将要被自己写的Spring容器管理的组件bean
    spring:里面定义自己写的Spring的类文件,包含子包anno注解包
    test:定义测试类

2. 模仿我们写Spring程序时创建测试类

package com.cjp.test;

import com.cjp.config.AppConfig;
import com.cjp.service.UserInterface;
import com.cjp.spring.ApplicationContext;

import java.lang.reflect.InvocationTargetException;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:30
 */
public class MySpringTest {

    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);

        UserInterface UserInterface = (UserInterface) applicationContext.getBean("userService");

        System.out.println("获取到的bean:  " + UserInterface);

        UserInterface.test();

    }
}

在这里,ApplicationContext就是我们将要手写的Spring上下文类,这里是模仿传入一个配置类参数,即全注解开发。

3. 开始实现ApplicationContext

  1. ApplicationContext内容
package com.cjp.spring;

import com.cjp.config.AppConfig;
import com.cjp.spring.anno.Autowired;
import com.cjp.spring.anno.Component;
import com.cjp.spring.anno.ComponentScan;
import com.cjp.spring.anno.Scope;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:24
 */


public class ApplicationContext {

    private Class appConfigClass;

    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionConcurrentHashMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, Object> singletonBeanConcurrentHashMap = new ConcurrentHashMap<>();
    private ArrayList<BeanPostProcessor> beanPostProcessorArrayList = new ArrayList<>();

    public ApplicationContext(Class<AppConfig> appConfigClass) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        this.appConfigClass = appConfigClass;

        scan(appConfigClass);

        // 把单例bean放入单例bean容器
        for (String beanName : beanDefinitionConcurrentHashMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")) {
                //单例的
                Object bean = createBean(beanName, beanDefinition);
                singletonBeanConcurrentHashMap.put(beanName, bean);
            }
        }


    }

    private void scan(Class<AppConfig> appConfigClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        ComponentScan componentScanAnnotation = appConfigClass.getAnnotation(ComponentScan.class);

        String classPath = componentScanAnnotation.value();

        String classPath_file = classPath.replace(".", "/");

        ClassLoader classLoader = ApplicationContext.class.getClassLoader();

        URL resource = classLoader.getResource(classPath_file);

        File file = new File(resource.getFile());

        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                String file_name = file1.getName();
                String class_path_file = classPath + "." + file_name.substring(0, file_name.length() - 6);
                // System.out.println(class_path_file);  //此时获取的是全限定类名:com.cjp.serviceCartService
                Class<?> aClass = Class.forName(class_path_file);
                if (aClass.isAnnotationPresent(Component.class)) {
                    if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
                        Object instance = aClass.newInstance();
                        beanPostProcessorArrayList.add((BeanPostProcessor) instance);
                    }
                    String bean_name = aClass.getAnnotation(Component.class).value();
                    if (bean_name.equals("") || bean_name == null) {
                        bean_name = Introspector.decapitalize(aClass.getSimpleName());
                        // System.out.println("默认的bean的名字:"+bean_name);
                    }

                    // System.out.println("应当加载该Bean    "+class_path_file);
                    // 先定义BeanDefinition
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setType(aClass);
                    // 没有scope注解,默认的单例的
                    if (aClass.isAnnotationPresent(Scope.class)) {
                        // 有scope注解,判断scope注解的值,如果为single,则为单例,否则为prototype是多例
                        String scope_value = aClass.getAnnotation(Scope.class).value();
                        if (scope_value.equals("singleton")) {
                            beanDefinition.setScope("singleton");
                        } else {
                            beanDefinition.setScope("prototype");
                        }
                    } else {
                        beanDefinition.setScope("singleton");
                    }
                    // System.out.println(beanDefinition);
                    beanDefinitionConcurrentHashMap.put(bean_name, beanDefinition);
                }

            }
        }

    }

    // 此方法体现了bean的生命周期
    private Object createBean(String beanName, BeanDefinition beanDefinition) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        Class type = beanDefinition.getType();

        Object instance = type.getConstructor().newInstance();

        // 实现依赖注入
        for (Field field : type.getDeclaredFields()) {
            System.out.println(field);
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                Class<?> field_type = field.getType();
                String simpleName = field_type.getSimpleName();
                String capitalize = Introspector.decapitalize(simpleName);  //bean的名字
                Object bean = getBean(capitalize);
                if (bean != null) {
                    field.set(instance, bean);
                } else {
                    throw new RuntimeException("依赖注入错误,未找到" + field_type);
                }
            }
        }
        // Aware
        if (instance instanceof BeanNameAware) {
            ((BeanNameAware) instance).setBeanName(beanName);
        }
        // 初始化前的前置处理器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
            instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
        }
        // 初始化
        if (instance instanceof InitializingBean) {
            ((InitializingBean) instance).initialBean();

        }
        // 初始化后的后置处理器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
            instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
        }
        // 初始化后 AOP  BeanPostProcessor Bean后置处理器

        return instance;
    }

    public Object getBean(String beanName) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
        if (beanDefinition == null) {
            throw new NullPointerException();
        } else {
            String scope = beanDefinition.getScope();
            //单例
            if (scope.equals("singleton")) {
                Object bean = singletonBeanConcurrentHashMap.get(beanName);
                if (bean == null) {
                    Object new_bean = createBean(beanName, beanDefinition);
                    singletonBeanConcurrentHashMap.put(beanName, new_bean);
                    return new_bean;
                }
                return bean;
            } else { // 多例
                return createBean(beanName, beanDefinition);
            }
        }
    }
}

  1. 注解类
    在这里插入图片描述
package com.cjp.spring.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:25
 */

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

    String value();

}
package com.cjp.spring.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:25
 */

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

    String value() default "";
}

package com.cjp.spring.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:25
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {

    String value() default "";
}

package com.cjp.spring.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:52
 */

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

    String value() default "singleton";
}

  1. 回调接口
    在这里插入图片描述
package com.cjp.spring;

/**
 * @author 曹见朋
 * @create 2023-11-23-11:24
 */
public interface BeanNameAware {

    void setBeanName(String beanName);

}

package com.cjp.spring;

/**
 * @author 曹见朋
 * @create 2023-11-23-11:34
 */
public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(String beanName, Object bean);

    Object postProcessAfterInitialization(String beanName, Object bean);
}

package com.cjp.spring;

/**
 * @author 曹见朋
 * @create 2023-11-23-11:29
 */
public interface InitializingBean {

    public void initialBean();


}

  1. 组件类
    在这里插入图片描述
  2. 配置类
package com.cjp.config;

import com.cjp.spring.anno.ComponentScan;

/**
 * @author 曹见朋
 * @create 2023-11-23-9:25
 */

@ComponentScan("com.cjp.service")
public class AppConfig {

}

4. 运行效果

在这里插入图片描述

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

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

相关文章

生物识别访问面临风险

安全公司 Blackwing Intelligence 发现了多个允许您绕过Windows Hello 身份验证的漏洞。 戴尔 Inspiron 灵越 15、联想 ThinkPad T14 和 Microsoft Surface Pro X笔记本电脑上会出现这种情况&#xff0c;原因是设备中集成了来自Goodix、Synaptics 和 ELAN的指纹传感器。 所有…

C#,数值计算——插值和外推,Powvargram的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Functor for variogram v(r)ar^b, /// where b is specified, a is fitted from the data. /// </summary> public class Powvargram { private do…

情感对话机器人的任务体系

人类在处理对话中的情感时&#xff0c;需要先根据对话场景中的蛛丝马迹判断出对方的情感&#xff0c;继而根据对话的主题等信息思考自身用什么情感进行回复&#xff0c;最后结合推理出的情感形成恰当的回复。受人类处理情感对话的启发&#xff0c;情感对话机器人需要完成以下几…

在新疆乌鲁木齐的汽车托运

在新疆乌鲁木齐要托运的宝! 看过来了 找汽车托运公司了 连夜吐血给你们整理了攻略!! ⬇️以下&#xff1a; 1 网上搜索 可以在搜索引擎或专业的货运平台上搜索相关的汽车托运公司信息。在网站上可以了解到公司的服务范围、托运价格、运输时效等信息&#xff0c;也可以参考其他车…

Ubuntu中安装搜狗输入法教程(详细图文教程)

习惯了使用搜狗输入法&#xff0c;这里总结了Ubuntu系统下安装搜狗输入法的详细教程&#xff0c;每个步骤都很详细&#xff0c;耐心安装。 搜狗输入法是一款功能强大、使用方便的输入法&#xff0c;能够有效提升用户在Ubuntu系统中的输入体验。 目录 一、下载搜狗安装包1.1 搜…

SpringCloud原理-OpenFeign篇(四、请求原理)

文章目录 前言正文一、书接上回&#xff0c;从代理对象入手二、ReflectiveFeign.FeignInvocationHandler#invoke()三、SynchronousMethodHandler#invoke(...) 的实现原理3.1 invoke(...)源码3.2 executeAndDecode(...) 执行请求并解码 四、如何更换client 的实现 附录附1&#…

【精选】框架初探篇之——MyBatis的CRUD及配置文件

MyBatis增删改查 MyBatis新增 新增用户 持久层接口添加方法 void add(User user);映射文件添加标签 <insert id"add" parameterType"com.mybatis.pojo.User">insert into user(username,sex,address) values(# {username},# {sex},# {address}) <…

NX二次开发UF_CURVE_ask_joined_parms 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_joined_parms Defined in: uf_curve.h int UF_CURVE_ask_joined_parms(tag_t joined_curve_feature, UF_STRING_p_t uf_curve_string, int * creation_method, double …

Git仓库瘦身大作战:133M 到 4M 的实战

开局两张图 瘦身前瘦身后 目录 开局两张图前言下载 BFG克隆代码Git 仓库瘦身清理存储库储存库 GC推送仓库 Git 瘦身验证结语开源项目 前言 在进行项目开发的过程中&#xff0c;代码仓库的体积可能会逐渐增大&#xff0c;特别是在版本控制系统中保留了大量的历史提交记录和不必…

apple macbook M系列芯片安装 openJDK17

文章目录 1. 查找openjdk版本2. 安装openjdk3. 多jdk之间的切换 在这里我们使用 brew 命令查找并安装。 1. 查找openjdk版本 执行&#xff1a;brew search openjdk&#xff0c;注意&#xff1a;执行命令后&#xff0c;如果得到的结果中没有红框内容&#xff0c;则需要更新一下…

使用STM32+SPI Flash模拟U盘

试验目的&#xff1a;使用STM32F103C8T6 SPI Flash&#xff08;WSQ16&#xff09;实现模拟U盘的功能 SPI Flash读写说明&#xff1a; Step1 设置SPI1 用于读取SPI Flash&#xff1b; Step2&#xff1a;设置SPI Flash 的使能信号 Step3&#xff1a;使能USB通信 Step4&#xf…

一起学docker系列之九docker运行mysql 碰到的各种坑及解决方法

目录 前言1 Docker 运行mysql命令2 坑一&#xff1a;无法读取/etc/mysql/conf.d目录的问题3 坑二&#xff1a;/tmp/ibnr0mis 文件无法创建/写入的问题4 坑三&#xff1a;Navicat 连接错误&#xff08;1045-access denied&#xff09;5 坑四&#xff1a;MySQL 登录失败问题结语 …

25 Linux I2C 驱动

一、I2C简介 I2C老朋友了&#xff0c;在单片机里面也学过&#xff0c;现在再复习一下。I2C使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线)&#xff0c;另外一条是 SDA(串行数据线)&#xff0c;这两条数据线需要接上拉电阻&#xff0c;总线空闲的时候 SCL…

NX二次开发UF_CURVE_ask_curve_struct_data 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_curve_struct_data Defined in: uf_curve.h int UF_CURVE_ask_curve_struct_data(UF_CURVE_struct_p_t curve_struct, int * type, double * * curve_data ) overview…

leetcode:随机链表的复制

题目描述 题目链接&#xff1a;138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 题目分析 这个题目很长&#xff0c;但是意思其实很简单&#xff1a;就是一个单链表&#xff0c;每个结点多了一个指针random随机指向链表中的任意结点或者NULL&#xff0c;我们血需…

CMSIS-DSP实数FFT相关API(单精度浮点float)

目录 1. CMSIS-DSP的实数FFT 2. 频域上求模值 3. 如何求解相位 4. 对比python的求解过程 5. 在频域上以模和相角的方式还原信号 6. 求能量值 平台&#xff1a;STM32F407-DiscoveryCMSIS-DSP-V1.6.0 1. CMSIS-DSP的实数FFT 文件&#xff1a;\CMSIS\DSP\Source\Transform…

模板初阶(1):函数模板,类模板

一、函数模板 1.1 概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实参类型产生函数的特定类型版本。 格式&#xff1a; template <typename T>或template <class T> template <class T>…

蓝桥杯第597题 跑步锻炼 C++ 日期模板题(模拟经典)

题目 跑步锻炼https://www.lanqiao.cn/problems/597/learning/?page1&first_category_id1&name%E8%B7%91%E6%AD%A5%E9%94%BB%E7%82%BC 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小蓝每天都锻炼身…

CTFUB-web前置技能-HTTP协议

burp抓包,抓第二次的 修改请求方式为CTFHUB

操作系统的基本特性--并发、共享、虚拟、异步

批处理系统具有高资源利用率和系统吞吐量&#xff1b;分时系统能够获得及时响应&#xff1b;实时系统具有实时特征。而这三种系统都具有并发、共享、虚拟和异步四个基本特征 一、并发 OS通过并发提高系统中的资源利用率&#xff0c;增加系统的吞吐量 1.并行和并发 并行&…