手写Spring框架

这篇具有很好参考价值的文章主要介绍了手写Spring框架。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

手写Spring框架

各位道友,我发现现在贼卷底层代码,看完源码发下几天后,额!!!我当时看了啥!

还是自己写个迷你的spring框架,这样印象更加深刻,上干货,代码仓库:https://gitee.com/smd_somin/SmdSpring.git

上面是我写的迷你版的spring框架,麻雀虽小,五脏俱全,主要包括下边的内容

  • 容器启动
  • BeanDefinition扫描
  • Bean声明周期
  • 单例与多例
  • 依赖注入
  • AOP
  • aware回调
  • 初始化
  • BeanPostProcessor(增强器)

下面是手写框架的过程和思路,仅供大家参考!!!

相信大家总会遇到这样问题,聊聊你理解的spring?

这个基本是100个技术,99个会遇到这个问题?我谈一下我得理解,仅供参考,我认为spring可以用两行表示

    //创建容器
    SmdApplicationContext context = new SmdApplicationContext(AppConfig.class);
    //获取对象
    UserInterface userService = (UserInterface) context.getBean("userService");

在这两行代码所牵连的内容其实就是spring的本质,对与bean的管理。

如果需要容器,那么我们需要有一个容器类,下面是手写spring容器的全部代码,这个也是逻辑的核心内容,下面会分享一下思路(建议对着源码看下):

上面的代码可以整体分为两个步骤,一个创建容器,另一个是从容器中获取bean。

首先说说创建容器的过程

创建容器 -> 扫描.class文件 -> 适配文件路径 -> 判断@Component注解 -> 符合注解进行反射获取对象 -> 记录bean的信息(类型,单例)-> 创建对象 -> 实例化对象 -> 依赖注入 -> aware增强类处理 -> 处理BeanPostProcessor的 postProcessorBeforeInitialazition方法 -> 初始化 -> BeanProcessor的beanPostProcessorAfterInitailzaiton方法 ->处理切面逻辑->bean创建成功

获取bean过程

主要区分单例还是多例,单例从单例池中取,多例新创建一个bean

SmdApplicationContext

package org.smd.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.smd.spring.annotation.Autowrite;
import org.smd.spring.annotation.Component;
import org.smd.spring.annotation.ScanComponent;
import org.smd.spring.annotation.Scope;
import org.smd.spring.aware.BeanNameAware;
import org.smd.spring.init.InitializingBean;

/**
 * @author smd
 * @zhName 容器
 * @description: 容器
 */
public class SmdApplicationContext {

  public Map<String, BeanDefinition> definitionMap = new HashMap();
  public Map<String, Object> singletonBeanMap = new HashMap();
  public List<BeanPostProcessor> beanPostProcessors=new ArrayList<BeanPostProcessor>();
  private Class configClass;

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

    //扫描文件夹下数据
    if (configClass.isAnnotationPresent(ScanComponent.class)) {
      ScanComponent scanComponent = (ScanComponent) configClass.getAnnotation(ScanComponent.class);

      //进行文件路径转化
      String path = scanComponent.vaule();
      System.out.println("-->scanComponent:" + path);
      path = path.replace(".", "/");
      System.out.println("-->scanComponent:" + path);

      //加载jar下.class文件
      ClassLoader classLoader = SmdApplicationContext.class.getClassLoader();
      URL resource = classLoader.getResource(path);
      File file = new File(resource.getFile());
      if (file.isDirectory()) {
        for (File f : file.listFiles()) {
          String filePath = f.getAbsolutePath();
          System.out.println("--> file path:" + filePath);
          if (filePath.endsWith(".class")) {

            String filesName = filePath
                .substring(filePath.indexOf("org"), filePath.indexOf(".class"));
            filesName = filesName.replace("\\", ".");
            System.out.println("-->file name" + filesName);
            try {
              Class<?> clazz = classLoader.loadClass(filesName);
              if (clazz.isAnnotationPresent(Component.class)) {

                if(BeanPostProcessor.class.isAssignableFrom(clazz)){
                  BeanPostProcessor beanPostProcessor=(BeanPostProcessor) clazz.newInstance();
                  beanPostProcessors.add(beanPostProcessor);
                }

                Component component = clazz.getAnnotation(Component.class);
                //获取bean name
                String name = component.vaule();
                if (name.equals("")) {
                  name = Introspector.decapitalize(clazz.getSimpleName());
                }
                //记录bean definition
                BeanDefinition definition = new BeanDefinition();
                definition.setType(clazz);
                if (clazz.isAnnotationPresent(Scope.class)) {
                  Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                  definition.setScope(scope.value());
                } else {
                  definition.setScope("singleton");
                }
                //放入bean definition map中
                definitionMap.put(name, definition);
              }
            } catch (ClassNotFoundException e) {
              e.printStackTrace();
            } catch (IllegalAccessException e) {
              e.printStackTrace();
            } catch (InstantiationException e) {
              e.printStackTrace();
            }
          }
        }
      }
    }

    //初始化bean
    for (String name : definitionMap.keySet()) {
      BeanDefinition definition = definitionMap.get(name);
      Object bean = this.createBean(name, definition);
      singletonBeanMap.put(name, bean);
    }
  }

  private Object createBean(String name, BeanDefinition definition) {
    Class clazz = definition.getType();
    try {
      //实例化
      Object bean = clazz.getConstructor().newInstance();

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

      // aware加强类回调
      if(bean instanceof BeanNameAware){
        ((BeanNameAware)bean).setBeanName(name);
      }
      // 初始化前调用bean post processor
      for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
        bean= beanPostProcessor.postProcessorBeforeInitialization(name,bean);
      }

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

      // 初始化后调用bean post processor
      for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
        bean= beanPostProcessor.postProcessorAftertInitialization(name,bean);
      }

      return bean;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  public Object getBean(String name) {

    //获取definition信息
    BeanDefinition definition = definitionMap.get(name);
    if (definition == null) {
      System.out.println("-->error:" + name);
      throw new NullPointerException();
    } else {
      //进行单例和多例区分
      if (definition.getScope().equals("singleton")) {
        Object bean = singletonBeanMap.get(name);
        if (bean == null) {
          return this.createBean(name, definition);
        } else {
          return bean;
        }
      } else {
        return this.createBean(name, definition);
      }
    }
  }
}


各位道友前路漫漫~ 努力向远方前进吧!!!

《真常之道,悟者自得,得悟道者,常清静矣。》文章来源地址https://www.toymoban.com/news/detail-457019.html

到了这里,关于手写Spring框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring源码系列:初探底层,手写Spring

    在学习Spring框架源码时,记住一句话:源码并不难,只需要给你各种业务场景或者项目经理,你也能实现自己的Spring。虽然你的实现可能无法与开源团队相媲美,但是你肯定可以实现一个0.0.1版本。因此,初次阅读源码时,不要陷入太深的细节中。先了解大体逻辑,再仔细研

    2023年04月12日
    浏览(44)
  • 【Spring专题】手写简易Spring容器过程分析

    首先必须得声明的是,下面的流程并不代表Spring源码中真正的流程。而是,我们通过现在的Spring提供给我们的某些基础功能,反推过来的流程。所以,并不全面,但是会具有一点参考性。 由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解

    2024年02月13日
    浏览(43)
  • 手写RPC框架--5.Netty业务逻辑

    RPC框架-Gitee代码(麻烦点个Starred, 支持一下吧) RPC框架-GitHub代码(麻烦点个Starred, 支持一下吧) 1.在 DcyRpcBootstrap 类的 start() 方法中加入netty代码 (待完善) 2.在 ReferenceConfig 类的 get() 方法中加入netty代码 (待完善) 每次启动程序都会建立一个新的Netty连接,显示是对不合适的 解决方案

    2024年02月09日
    浏览(46)
  • 手写Spring底层机制

    加入到createBean()中 加入到createBean()中 AOP需要在后置处理器的before方法中实现 1.单例/多例怎么实现的?@scope为什么可以实现? 回答:@scope 的value属性可以设置为singleton /prototype 通过getBean()方法 如果bean中的属性scope为singleton 就从单例池直接拿,如果是prototype 就调用createB

    2024年04月09日
    浏览(40)
  • 手写模拟Spring的底层原理2.1

    先来引入两个问题 第一个懒加载还是立即加载的问题,这个问题还是在于就是说,当我们xml配置了一个对象bean的时候,它在spring容器里面是什么时候开始会给我们创建这个对象 那如果我们想对某个对象启动懒加载,可以添加@lazy这个注解  这个注解一加上,它就只会在得到

    2024年02月08日
    浏览(41)
  • Spring手写模拟源码篇(你值得拥有)

    下面是本文章关于Spring底层原理的章节 类-》推断构造方法-》根据构造方法创建普通对象-》依赖注入(@Autowired等进行属性注入)-》初始化前(@PostConstruct)-初始化(InitializingBean)-》初始化后(AOP)-》代理对象(没有开启AOP就会把普通对象放入单例池)-》放入单例池-》Bean对象

    2024年02月01日
    浏览(39)
  • Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架

    基于XML方式 项目结构 项目代码 pom.xml UserBean.java spring.xml SpringTest01.java 运行结果 基于注解方式 项目结构 项目代码 ScanBean.java SpringConfig.java SpringTest02.java 运行结果 核心原理 底层使用map集合管理对象,key=beanId,value=实例对象 基于XML方式 原理 基于反射+工厂模式+DOM技术 使用

    2024年02月13日
    浏览(41)
  • 【2】Spring手写模拟-依赖注入、初始化、AOP

    首先回顾一下我们之前的流程 ApplicationContext 构造方法 获取Spring配置类 @ComponetScan 注解,扫描包,获取其路径及其对应的字节码文件 逐个扫描字节码文件 利用字节码文件获取类,查看是否包含 @Componet 注解,并获取或者生成 BeanName 获取 BeanDefinition ,包含其类和类型(单例,多

    2024年02月16日
    浏览(49)
  • javaer你还在手写分表分库?来看看这个框架怎么做的 干货满满

    高并发三驾马车:分库分表、MQ、缓存。今天给大家带来的就是分库分表的干货解决方案,哪怕你不用我的框架也可以从中听到不一样的结局方案和实现。 一款支持自动分表分库的orm框架 easy-query 帮助您解脱跨库带来的复杂业务代码,并且提供多种结局方案和自定义路由来实现比

    2024年02月06日
    浏览(49)
  • 深入浅出OkHttp,【带你手写】构建高效、高性能的网络请求框架

    OKHttp是一个用Java编写的网络框架,可用于 Android,以及一些基于Java的web应用开发中。它使用了HTTP/2标准的支持和连接池技术,可以让应用快速向Web服务器发送网络请求,并得到响应。OKHttp提供了一个简单的API,允许开发者发送同步或异步的HTTP请求,并处理来自Web服务器的响

    2023年04月20日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包