Spring-手写模拟Spring底层原理

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

概述

模拟大致的底层原理,为学习Spring源码做铺垫。

实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面

未实现的功能:构造器推断、循环依赖

重点:BeanDefinition、BeanPostProcessor

学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点

启动类:

public class Yeah
{
    public static void main(String[] args)
    {
        GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);
        UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");
        userService.test();
    }
}

关键方法:

public class GaxApplicationContext
{
    private Class configClass;
    
    private static final String SINGLETON = "singleton";
    
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    
    private Map<String, Object> singletonObjects = new HashMap<>();
    
    // Spring源码用的是LinkedList
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
    
    public GaxApplicationContext(Class configClass)
    {
        this.configClass = configClass;
        
        // 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中
        scan(configClass);
        
        // 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet())
        {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (SINGLETON.equals(beanDefinition.getScope()))
            {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }
    
    private Object createBean(String beanName, BeanDefinition beanDefinition)
    {
        Class clazz = beanDefinition.getType();
        Object instance = null;
        
        try
        {
            // 直接使用默认的无参构造器,多个构造器的场景未实现
            instance = clazz.getConstructor().newInstance();
            
            // 属性填充,依赖注入
            for (Field field : clazz.getDeclaredFields())
            {
                if (field.isAnnotationPresent(Autowired.class))
                {
                    field.setAccessible(true);
                    field.set(instance, getBean(field.getName()));
                }
            }
            
            // aware回调
            if (instance instanceof BeanNameAware)
            {
                ((BeanNameAware)instance).setBeanName(beanName);
            }
            
            // 初始化前
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList)
            {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }
            
            // 初始化
            if (instance instanceof InitializingBean)
            {
                ((InitializingBean)instance).afterPropertiesSet();
            }
            
            // 初始化后
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList)
            {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }
        }
        catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e)
        {
            e.printStackTrace();
        }
        
        return instance;
    }
    
    public Object getBean(String beanName)
    {
        if (!beanDefinitionMap.containsKey(beanName))
        {
            throw new NullPointerException();
        }
        
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (SINGLETON.equals(beanDefinition.getScope()))
        {
            Object singletonBean = singletonObjects.get(beanName);
            if (null == singletonBean)
            {
                singletonBean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;
        }
        else
        {
            // 原型Bean
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }
    
    private void scan(Class configClass)
    {
        if (configClass.isAnnotationPresent(ComponentScan.class))
        {
            ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
            String path = componentScanAnnotation.value();
            // path = com/gax/service
            path = path.replace(".", "/");
            
            ClassLoader classLoader = GaxApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);
            assert resource != null;
            File file = new File(resource.getFile());
            
            if (file.isDirectory())
            {
                for (File f : Objects.requireNonNull(file.listFiles()))
                {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    // 类加载器入参需要的格式:com.gax.service.XXX
                    absolutePath = absolutePath.replace("\\", ".");
                    
                    try
                    {
                        Class<?> clazz = classLoader.loadClass(absolutePath);
                        if (clazz.isAnnotationPresent(Component.class))
                        {
                            if (BeanPostProcessor.class.isAssignableFrom(clazz))
                            {
                                BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }
                            
                            Component componentAnnotation = clazz.getAnnotation(Component.class);
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName))
                            {
                                // 默认beanName
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }
                            
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);
                            
                            if (clazz.isAnnotationPresent(Scope.class))
                            {
                                Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                String value = scopeAnnotation.value();
                                beanDefinition.setScope(value);
                            }
                            else
                            {
                                // 默认单例Bean
                                beanDefinition.setScope(SINGLETON);
                            }
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    }
                    catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException
                        | InstantiationException | IllegalAccessException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

gitee地址:文章来源地址https://www.toymoban.com/news/detail-719532.html

git clone https://gitee.com/seek6174/spring-seek.git

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

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

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

相关文章

  • 【2】Spring手写模拟-依赖注入、初始化、AOP

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

    2024年02月16日
    浏览(37)
  • 【Spring】Spring底层核心原理解析

    简单代码: spring.xml内容: AppConfig.class内容: AppConfig.class替代了spring.xml文件,表示spring的配置文件; ApplicationContext在Spring、SpringMVC、SpringBoot中的创建方式: Spring,通过 ClassPathXmlApplicationContext 创建; SpringMVC,通过 XmlWebApplicationContext 创建; SpringBoot,通过 AnnotationConfigAppl

    2024年02月15日
    浏览(23)
  • Spring - Spring底层核心原理解析

    1. Bean的生命周期底层原理 2. 依赖注入底层原理 3. 初始化底层原理 4. 推断构造方法底层原理 5. AOP底层原理 6. Spring事务底层原理 对于这三行代码应该,大部分同学应该都是比较熟悉,这是学习Spring的hello world。可是,这三行代码底层都做了什么,比如: 第一行代码,会构造一

    2024年02月07日
    浏览(36)
  • 【Spring专题】Spring底层核心原理解析

    Spring啊,可以说是我们大部分Java玩家【最熟悉的陌生人】了吧。八个字形容:似懂非懂,会也不会 你说简单应用,我们大家都会,那真要展开说两句的话,那只能来这么两句:这是第一句,接着是第二句,好了我说完了。 但是啊xdm, 据说Spring是一份非常非常非常优秀的源码

    2024年02月13日
    浏览(33)
  • 走进Spring的世界 —— Spring底层核心原理解析(一)

    这是学习Spring的hello world。可是,这三行代码底层都做了什么,比如: 第一行代码,会构造一个ClassPathXmlApplicationContext对象,ClassPathXmlApplicationContext该如何理解,调用该构造方法除开会实例化得到一个对象,还会做哪些事情? 第二行代码,会调用ClassPathXmlApplicationContext的ge

    2024年02月07日
    浏览(41)
  • Spring底层原理(三)

    Bean 的生命周期 启动容器后会得到以下结果   Bean的生命周期为:构造方法 - 依赖注入-初始化 -销毁 与Bean生命周期相关的后置处理器 PostProcessor 中文意思为后置处理器 InstantiationAwareBeanPostProcessor 与 DestructionAwareBeanPostProcessor 都是 BeanPostProcessor 的子接口 Bean 后置处理器与模板方

    2024年02月08日
    浏览(25)
  • 【Spring】aop的底层原理

    🎄欢迎来到@边境矢梦°的csdn博文🎄  🎄本文主要梳理 Spring 中的切面编程aop的底层原理和重点注意的地方 🎄 🌈我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一下 🫰🫰🫰 ,下次更新不迷路🎆 Ps: 月亮越亮说明知识点越重要 (重要

    2024年02月09日
    浏览(30)
  • spring中的事务及底层原理

    在Spring框架中,事务管理是一个关键的特性,它允许开发者在应用程序中声明性地管理事务。Spring事务管理的核心是基于AOP(面向切面编程)和IOC(控制反转)的思想。以下是Spring中事务管理的一些重要概念和底层原理: 事务管理器(Transaction Manager): Spring事务管理的底层

    2024年01月19日
    浏览(30)
  • Spring IOC底层原理实现过程

    Spring IOC(Inversion of Control,控制反转)是 Spring 框架的核心,它的实现原理是基于反射和配置文件实现的。 在 Spring IOC 中,控制权被反转了。传统的应用程序开发中,对象的创建、管理、销毁等全部由应用程序自己来控制,这个过程称为主动管理(Active Management)。而在 Spr

    2024年02月03日
    浏览(31)
  • Spring(18) @Order注解介绍、使用、底层原理

    @Order :是 spring-core 包下的一个注解。@Order 作用是 定义 Spring IOC 容器中 Bean 的执行顺序 。 注意: Spring 的 @Order 注解或者 Ordered 接口,不决定 Bean 的加载顺序和实例化顺序,只决定 Bean 注入到 List 中的顺序。 @Order 注解接受一个整数值作为参数, 数值越小表示优先级越高 。

    2024年02月20日
    浏览(26)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包