300行代码实现简易Spring框架

news2024/11/18 1:41:04

源码地址

该简易Spring框架实现的功能有

  1. 容器启动
  2. 包扫描
  3. 单例、多例Bean
  4. Bean的创建
  5. 依赖注入
  6. Aware回调函数
  7. 初始化
  8. 后处理器
  9. AOP

目录结构如下,service包为模拟业务逻辑,spring包为spring的实现(核心),其中ApplicationContext为核心类。

在这里插入图片描述

package com.ego.spring;

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.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 袁梦达
 */
public class ApplicationContext {


    //配置文件  扫描包
    private Class configClass;
    //bean工厂
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //单例bean
    private ConcurrentHashMap<String, Object> singletonMap = new ConcurrentHashMap<>();
    //后处理器
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public ApplicationContext(Class configClass){
        this.configClass = configClass;

        //扫描
        if(configClass.isAnnotationPresent(ComponentScan.class)){

            //获取ComponentScan的值
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);

            //com.ego.service
            String scanPath = componentScanAnnotation.value();
            //com/ego/service
            scanPath = scanPath.replace(".", "/");
            //去out文件夹里找到扫描的包
            ClassLoader classLoader = ApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(scanPath);

            //扫描包里每一个class文件是否为Bean
            File file = new File(resource.getFile());
            if(file.isDirectory()){
                for (File f : file.listFiles()) {
                    String fileName = f.getAbsolutePath();
                    if(fileName.endsWith(".class")){
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        className = className.replace("\\", ".");

                        try {

                            Class<?> clazz = classLoader.loadClass(className);
                            //判断是否为Bean
                            if(clazz.isAnnotationPresent(Component.class)){

                                //如果是后处理器则加入list中
                                if(BeanPostProcessor.class.isAssignableFrom(clazz)){
                                    BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                    beanPostProcessorList.add(instance);
                                }

                                Component componentAnnotation = clazz.getAnnotation(Component.class);
                                String beanName = componentAnnotation.value();

                                //默认Bean的name
                                if("".equals(beanName)){
                                    beanName = Introspector.decapitalize(clazz.getSimpleName());
                                }

                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setClazz(clazz);

                                //作用域
                                if(clazz.isAnnotationPresent(Scope.class)){
                                    Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                    beanDefinition.setScope(scopeAnnotation.value());
                                }else{
                                    beanDefinition.setScope("singleton");
                                }
                                beanDefinitionMap.put(beanName, beanDefinition);
                            }

                        } catch (ClassNotFoundException | InvocationTargetException | InstantiationException |
                                 IllegalAccessException | NoSuchMethodException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }

            }
        }

        //将所有单例Bean加入到单例池
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if("singleton".equals(beanDefinition.getScope())){
                Object bean = createBean(beanName, beanDefinition);
                singletonMap.put(beanName, bean);
            }
        }


    }

    private Object createBean(String beanName, BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object bean = null;
        try {
            //实例化
            bean = clazz.getConstructor().newInstance();

            //依赖注入
            for (Field field : clazz.getFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    field.set(bean, getBean(field.getName()));
                }
            }

            //执行回调接口
            if(bean instanceof BeanNameAware){
                ((BeanNameAware)bean).setBeanName(beanName);
            }

            //前置处理器
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                bean = beanPostProcessor.postProcessorBeforeInitialization(beanName, bean);
            }

            //初始化
            if(bean instanceof InitializingBean){
                ((InitializingBean)bean).afterPropertiesSet();
            }

            //后置处理器
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                bean = beanPostProcessor.postProcessorAfterInitialization(beanName, bean);
            }

        } catch (InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return bean;
    }
    public Object getBean(String beanName){
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        if(beanDefinition == null){
            throw new NullPointerException("bean不存在");
        }else {
            String scope = beanDefinition.getScope();
            if("singleton".equals(scope)){
                //单例Bean直接从单例池中获取
                Object bean = singletonMap.get(beanName);

                //此条件发生在初始化容器时,生成单例Bean的时候
                //在某个Bean依赖注入时,如果被注入的单例Bean还没有实例化,
                //那么就要先实例化被注入的单例Bean,再实例化当前Bean
                if(bean == null){
                    bean= createBean(beanName, beanDefinition);
                }
                return bean;
            }else{
                return createBean(beanName, beanDefinition);
            }
        }
    }
}

package com.ego.spring;

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

/**
 * @author 袁梦达
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {

}

package com.ego.spring;

/**
 * @author 袁梦达
 */
public class BeanDefinition {
    private Class clazz;
    private String scope;

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

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

package com.ego.spring;

public interface BeanNameAware {
    void setBeanName(String beanName);
}

package com.ego.spring;

public interface BeanPostProcessor {
    Object postProcessorBeforeInitialization(String beanName, Object bean);
    Object postProcessorAfterInitialization(String beanName, Object bean);
}

package com.ego.spring;

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

/**
 * @author 袁梦达
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    String value() default "";
}

package com.ego.spring;

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

/**
 * @author 袁梦达
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value() default "";
}

package com.ego.spring;

/**
 * @author 袁梦达
 */
public interface InitializingBean {
    void afterPropertiesSet();
}

package com.ego.spring;

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

/**
 * @author 袁梦达
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default "";
}

package com.ego.service;

import com.ego.spring.BeanPostProcessor;
import com.ego.spring.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessorBeforeInitialization(String beanName, Object bean) {
        if(beanName.equals("userService")){
            System.out.println("postProcessorBeforeInitialization...");
        }
        return bean;
    }

    @Override
    public Object postProcessorAfterInitialization(String beanName, Object bean) {
        if(beanName.equals("userService")){
            System.out.println("postProcessorAfterInitialization...");
            return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("aop执行...");
                    return method.invoke(bean, args);
                }
            });
        }
        return bean;
    }
}

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

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

相关文章

MySQL数据库中.frm和.myi和.myd和.ibd文件是什么文件?

mysql 数据库 存储引擎是myisam, 在data目录下会看到3类文件&#xff1a;.frm、.myi、.myd &#xff08;1&#xff09;.frm–表定义&#xff0c;是描述表结构的文件。 &#xff08;2&#xff09;.MYD–"D"数据信息文件&#xff0c;是表的数据文件。 &#xff08;3&am…

mfc程序发布时带上必要的dll

mfc在开发机器上&#xff0c;运行时没问题的&#xff0c; 但如果到其他windows机器运行会报错&#xff0c;提示几个dll库文件找不到 如何处理&#xff1f; 不要慌&#xff0c;问题不大&#xff0c;不要盲目去下载dll&#xff0c;或到c盘windows下找&#xff0c; 完全没必要…

浅析大数据时代下的视频技术发展趋势以及AI加持下视频场景应用

视频技术的发展可以追溯到19世纪初期的早期实验。到20世纪初期&#xff0c;电视技术的发明和普及促进了视频技术的进一步发展。 1&#xff09;数字化&#xff1a;数字化技术的发明和发展使得视频技术更加先进。数字电视信号具有更高的清晰度和更大的带宽&#xff0c;可以更快地…

WebServer项目

web服务器是IO密集型的任务&#xff1a;> CPU个数 有限状态机来更高效地处理状态的转移&#xff1a; 【差不多捋顺&#xff0c;按模块自己写出文字讲解&#xff0c;讲出优化思路优化的效果&#xff0c;瓶颈是啥解决策略是啥】 【redis 如何实现】【innodb底层如何实现】【e…

物理分代垃圾回收器

内存结构 内存分配 堆上分配 大多数情况在eden【年轻代中的一个区域】上分配&#xff0c;偶尔会直接在old【老年代】上分配&#xff0c;细节取决于GC的实现。栈上分配&#xff08;发生了指针逃逸&#xff0c;又叫指针逃逸分析——JVM优化&#xff09; 原子类型的局部变量。 G…

【Linux命令200例】tee将输入内容输出到屏幕和文件

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜…

Dockerfile构建nginx镜像(编译安装)

Dockerfile构建nginx镜像 1、建立工作目录 [rootdocker ~]# mkdir nginx [rootdocker ~]# cd nginx/ 2、编写Dockerfile文件 [rootdocker nginx]# vim run.sh [rootdocker nginx]# vim Dockerfile #基于的基础镜像 FROM centos:7#镜像作者信息 MAINTAINER Crushlinux <…

【iOS】json数据解析以及简单的网络数据请求

文章目录 前言一、json数据解析二、简单的网络数据请求三、实现访问API得到网络数据总结 前言 近期写完了暑假最后一个任务——天气预报&#xff0c;在里面用到了简单的网络数据请求以及json数据的解析&#xff0c;特此记录博客总结 一、json数据解析 JSON是一种轻量级的数据…

《Spring Boot源码解读与原理分析》书籍推荐

Spring Boot是目前Java EE开发中颇受欢迎的框架之一。依托于底层Spring Framework的基础支撑&#xff0c;以及完善强大的特性设计&#xff0c;Spring Boot已成为业界流行的应用和微服务开发基础框架。 《Spring Boot源码解读与原理分析》共14章&#xff0c;分为4个部分。第一部…

css white-space属性

先看不换行的效果&#xff0c;调用.space类 再来看使用 white-space:nowrap的效果 运行结果如下&#xff1a;

Spring Boot 集成 Thymeleaf 模板引擎

Spring Boot 集成 Thymeleaf 模板引擎 1. Thymeleaf 介绍 Thymeleaf 是适用于 Web 和独立环境的现代服务器端 Java 模板引擎。 Thymeleaf 的主要目标是为开发工作流程带来优雅的自然模板&#xff0c;既可以在浏览器中正确显示的 HTML&#xff0c;也可以用作静态原型&#xff…

【芯片设计- RTL 数字逻辑设计入门 3- Verdi 常用使用命令】

文章目录 Verdi 全局显示Verdi 前导 0 的显示Verdi 数据笔数统计Verdi 波形数据dump Verdi 全局显示 bsubi -n 16 -J sam visualizer -tracedir ./veloce.wave/debug_waveform.stw 打开波形后&#xff0c;如果想要看到所有信号的数据&#xff0c;可以点击下图中红框中的按钮&a…

DASCTF 2023 0X401七月暑期挑战赛web复现

目录 <1> Web (1) EzFlask(python原型链污染&flask-pin) (2) MyPicDisk(xpath注入&文件名注入) (3) ez_cms(pearcmd文件包含) (4) ez_py(django框架 session处pickle反序列化) <1> Web (1) EzFlask(python原型链污染&flask-pin) 进入题目 得到源…

系统接口自动化测试方案

XXX接口自动化测试方案 1、引言 1.1 文档版本 版本 作者 审批 备注 V1.0 XXXX 创建测试方案文档 1.2 项目情况 项目名称 XXX 项目版本 V1.0 项目经理 XX 测试人员 XXXXX&#xff0c;XXX 所属部门 XX 备注 1.3 文档目的 本文档主要用于指导XXX-Y…

C++ __builtin_popcount函数作用

__builtin_popcount函数是系统自带的一个返回值是int/long/long long二进制1的个数的函数。 对于int&#xff0c;long&#xff0c; long long分别用一下三种函数&#xff1a; __builtin_popcount(unsigned int n)//返回值为int __builtin_popcountl(unsigned int n)//返回值为…

【共享广告主】小白的创业项目:互联网广告,详细介绍

科思创业汇 大家好&#xff0c;这里是科思创业汇&#xff0c;一个轻资产创业孵化平台。赚钱的方式有很多种&#xff0c;我希望在科思创业汇能够给你带来最快乐的那一种&#xff01; 互联网广告做什么生意&#xff1f; 互联网广告行业面向哪些客户群体&#xff1f; 互联网广…

Anaconda创建虚拟环境

参考文章 1 Win10RTX3060配置CUDA等深度学习环境 pytorch 管网&#xff1a;PyTorch 一 进入 Anaconda 二 创建虚拟环境 conda create -n pytorch python3.9注意要注意断 VPN切换镜像&#xff1a; 移除原来的镜像 # 查看当前配置 conda config --show channels conda config…

leetcode 46. Permutations(排列)

返回数组nums中数字的所有可能的排列组合。 思路&#xff1a; 排列组合这种一般会想到DFS。 这个排列中每个数字只能用一次&#xff0c; 可用如下DFS流程 stack.push(num); dfs(nums, num); stack.pop();退出条件&#xff1a; 当stack的size和nums数组一样时&#xff0c;说…

P1257 平面上的最接近点对

题目 思路 详见加强加强版 代码 #include<bits/stdc.h> using namespace std; #define int long long const int maxn4e510; pair<int,int> a[maxn]; int n; double d1e16; pair<int,int> vl[maxn],vr[maxn]; void read() { cin>>n;for(int i1;i<…

/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28‘ not found

某项目中&#xff0c;我要给别人封装一个深度学习算法的SDK接口&#xff0c;运行在RK3588平台上&#xff0c;然后客户给我的交叉编译工具链是 然后我用他们给我的交叉编译工具链报下面的错误&#xff1a; aarch64-buildroot-linux-gnu-gcc --version /data/chw/aarch64/bin/cca…