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
相关推荐
.道阻且长.9 分钟前
C++ string 操作指南:接口解析
java·c语言·开发语言·c++
蚰蜒螟11 分钟前
Java 对象的内存密语:从字段偏移量计算到 Unsafe 访问的完整链路
java·开发语言
IT 行者11 分钟前
GitHub Spec Kit 实战(六):/speckit.implement 怎么用、怎么审、怎么发现 spec 阶段的遗漏——五部曲收官
java·驱动开发·github·ai编程·claude
星辰_mya28 分钟前
CountDownLatch深度解析
java·开发语言·后端·架构
伊甸330 分钟前
从企业级项目学敏感词过滤:DFA算法与双层缓存实战
java·算法·缓存
cfm_291430 分钟前
JVM新一代垃圾收集器深度解析:G1与ZGC
java·jvm
x***r15136 分钟前
.NET 10 SDK 安装教程(dotnet-sdk-10.0.100-win-x64详细步骤)
java·服务器·前端
摇滚侠42 分钟前
MyBatis 入门到项目实战 MyBatis 的缓存 56-61
java·缓存·mybatis
让我上个超影吧1 小时前
Claude code:Hooks
java·数据库·ai编程
RH2312111 小时前
2026.6.8Linux
java·数据库·中间件