手写一个简单版的Spring

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. 运行效果

在这里插入图片描述

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

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

相关文章

springboot+vue基本微信小程序的外卖点餐平台系统

项目介绍 餐饮行业是一个传统的行业。根据当前发展现状&#xff0c;网络信息时代的全面普及&#xff0c;餐饮行业也在发生着变化&#xff0c;单就点餐这一方面&#xff0c;利用手机点单正在逐步进入人们的生活。传统的点餐方式&#xff0c;不仅会耗费大量的人力、时间&#xf…

C++入门第九篇---Stack和Queue模拟实现,优先级队列

前言&#xff1a; 我们已经掌握了string vector list三种最基本的数据容器模板&#xff0c;而对于数据结构的内容来说&#xff0c;其余的数据结构容器基本都是这三种容器的延申和扩展&#xff0c;在他们的基础上扩展出更多功能和用法&#xff0c;今天我们便来模拟实现一下C库中…

【OpenSTL】方便好用的时空预测开源库

OpenSTL&#xff1a;方便好用的时空预测开源库 时空预测学习是一种学习范式&#xff0c;它使得模型能够通过在无监督的情况下从给定的过去帧预测未来帧&#xff0c;从而学习空间和时间的模式。尽管近年来取得了显著的进展&#xff0c;但由于不同的设置、复杂的实现和难以复现性…

Go语言的学习笔记2——Go语言源文件的结构布局

用一个只有main函数的go文件来简单说一下Go语言的源文件结构布局&#xff0c;主要分为包名、引入的包和具体函数。下边是main.go示例代码&#xff1a; package mainimport "fmt"func main() { fmt.Println("hello, world") }package main就是表明这个文件…

AlDente Pro v1.22.2(mac电池最大充电限制工具)

AlDente Pro是一款适用于Mac操作系统的小工具&#xff0c;可以帮助您限制电池充电量以延长电池寿命。通常情况下&#xff0c;电池在充满的状态下会继续接受电源充电&#xff0c;这可能会导致电池寿命缩短。使用AlDente Pro&#xff0c;您可以设置电池只充到特定的充电水平&…

高清动态壁纸软件Live Wallpaper Themes 4K mac中文版功能

Live Wallpaper & Themes 4K mac是一款提供各种高清动态壁纸和主题的应用程序。该应用程序提供了大量的动态壁纸和主题&#xff0c;包括自然、动物、城市、抽象等各种类别&#xff0c;可以满足用户不同的需求。除了壁纸和主题之外&#xff0c;该应用程序还提供了许多其他功…

拦截器详解

一、概述 什么是拦截器&#xff1f; 是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。Spring框架中提供的&#xff0c;用来动态拦截控制方法的执行。 到底是干啥用的&#xff1f; 拦截请求用的&#xff0c;在指定的方法调用前后&#xff0c;执行在拦截器中编写的程序 …

苹果App加急审核

苹果App加急审核 &#xff08;注意加急的次数&#xff0c;有的说一年能加急两次&#xff0c;有的说不止两次。遇到紧急问题了就用&#xff0c;非紧急 等一等也行&#xff09; 1.登录苹果账号 Sign In - Apple &#xff08; https://developer.apple.com/contact/app-store/?…

力扣每日一道系列 --- LeetCode 206. 反转链表

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅LeetCode每日一道 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 LeetCode 206. 反转链表 思路一&#xff1a;头插 初始化两个指针&#xff0c;cur 和 newhead。…

单片机、ARM、嵌入式开发、Android 底层开发有什么关系?

单片机、ARM、嵌入式开发、Android 底层开发有什么关系&#xff1f; 从我目前的见识来看&#xff1a; 单片机是个系统&#xff08;比如&#xff1a;51、AVR、PLC...&#xff09;&#xff0c;其中包含了去除了输入输出之外的运算器、控制器、存储器&#xff0c;我们用程序可以非…

CANdelaStudio 使用教程3 新建Service

文章目录 简述Service 的相关配置项1、Protocol Services2、Diagnostic Class Templates3、Supported Diagnostic Classes 新建 Service1、新建 Service2、新建类并添加服务3、 选择支持的服务4、Diagnostic Class Templates&#xff1a;Identification 编辑 Service1、新增服务…

区块链技术将如何影响未来的数字营销?

你是否听腻了区块链和数字营销等流行语&#xff0c;却不明白它们对未来意味着什么&#xff1f;那么&#xff0c;准备好系好安全带吧&#xff0c;因为区块链技术将彻底改变我们对数字营销的看法。从建立消费者信任到提高透明度和效率&#xff0c;其可能性是无限的。 让我们来探…

有序表的详解

目录 有序表的介绍 树的左旋和右旋操作 AVL树的详解 SB树的详解 红黑树的介绍 SkipList的详解 有序表的介绍 有序表是除具备哈希表所具备的功能外&#xff0c;有序表中的内容都是按照key有序排列的&#xff0c;并且增删改查等操作的时间复杂度都是&#xff0c;红黑树&…

【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步?

【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步&#xff1f; 文章目录 【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步&#xff1f;一、简介软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步1 安…

Educational Codeforces Round 158 (Rated for Div. 2)(A~E)(贪心,树形DP)

A - Line Trip 题意&#xff1a;有一条路&#xff0c;可以用一条数线来表示。你位于数线上的点 0 &#xff0c;你想从点 0 到点 x &#xff0c;再回到点 0。你乘汽车旅行&#xff0c;每行驶 1个单位的距离要花费 1 升汽油。当您从点 0出发时&#xff0c;汽车已加满油(油箱中的…

spring boot的自动装配原理

一&#xff1a;简介 SpringBoot 这款框架几乎是现在企业级开发的标配&#xff0c;使用SpringBoot进行开发&#xff0c;能够大量减少xml配置文件的编写&#xff0c;并且能为我们提供一站式服务。SpringBoot我们只需要导入相关模块的starter&#xff0c;就可以使用相关功能&…

深度学习基于Python+TensorFlow+Django的水果识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介简介技术组合系统功能使用流程 二、功能三、系统四. 总结 一项目简介 # 深度学习基于PythonTensorFlowDjango的水果识别系统介绍 简介 该水果识别系统基于…

医保线上购药系统:引领医疗新潮流

在科技的驱动下&#xff0c;医疗健康服务正经历一场数字化的革新。医保线上购药系统&#xff0c;不仅是一种医疗服务的新选择&#xff0c;更是技术代码为我们的健康管理带来的全新可能。本文将通过一些简单的技术代码示例&#xff0c;深入解析医保线上购药系统的工作原理和优势…

C#,《小白学程序》第五课:队列(Queue)其一,排队的技术与算法

日常生活中常见的排队&#xff0c;软件怎么体现呢&#xff1f; 排队的基本原则是&#xff1a;先到先得&#xff0c;先到先吃&#xff0c;先进先出 1 文本格式 /// <summary> /// 《小白学程序》第五课&#xff1a;队列&#xff08;Queue&#xff09; /// 日常生活中常见…

uniapp IOS从打包到上架流程(详细简单) 原创

uniapp打包好的ipa文件&#xff0c;需要上架到appstore&#xff0c;用户才能通过app store下载使用&#xff0c;因此我们需要将ipa上架到appstore. 我们这篇文章&#xff0c;将教会大家使用windows电脑将uniapp打包好的ipa文件&#xff0c;上架到appstore的方法和详细流程。 …