Spring-手写模拟Spring底层原理

概述

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

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

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

重点:BeanDefinition、BeanPostProcessor

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

启动类:

md-end-block 复制代码
public class Yeah
{
    public static void main(String[] args)
    {
        GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);
        UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");
        userService.test();
    }
}

关键方法:

md-end-block 复制代码
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地址:

md-end-block 复制代码
git clone https://gitee.com/seek6174/spring-seek.git
相关推荐
master-dragon7 分钟前
spring-ai 工作流
人工智能·spring·ai
考虑考虑11 分钟前
使用jpa中的group by返回一个数组对象
spring boot·后端·spring
云动雨颤31 分钟前
Java并发性能优化|读写锁与互斥锁解析
java
ldj202044 分钟前
Centos 安装Jenkins
java·linux
hqxstudying1 小时前
Intellij IDEA中Maven的使用
java·maven·intellij-idea
SimonKing1 小时前
拯救大文件上传:一文彻底彻底搞懂秒传、断点续传以及分片上传
java·后端·架构
深栈解码1 小时前
JUC并发编程 内存布局和对象头
java·后端
北方有星辰zz1 小时前
数据结构:栈
java·开发语言·数据结构
Seven971 小时前
一个static关键字引发的线上故障:深度剖析静态变量与配置热更新的陷阱
java
山野万里__1 小时前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记