spring 源码实现

spring 源码实现

通过实现 mini 版本 spring 框架,成为一个更合格的spring工程师

  1. 实现 spring 框架整个扫描过程,@ComponentScan
  2. 实现 解析全匹配类路径,并使用类加载器加载(双亲委派原理)扫秒类,生成 BeanDefinitionMap
  3. 贯穿熟悉 Reflection 反射调用,包括:getClass,annotation,field,constructor,method
  4. 实现 Aware 容器感知技术(set 方法 + 反射应用)
  5. 实现 使用实现 InitializingBean 的方式来初始化 Bean 对象
  6. 实现 使用 Java-jdk 动态代理方式实现 AOP 切面 BeanPostProcessor
  7. 熟悉 Bean 命名定义,创建过程,声明周期
  8. 实现 三级缓存依赖解决循环依赖问题
    在这里插入图片描述

spring 框架运行过程描述

  • com.source.content 应用程序代码
  • com.source.spring 框架源码

框架运行过程步骤描述包含两部分内容:默认为 spring 框架,使用[应用]标注的表示,这一步骤描述是属于应用程序

  1. 创建管理容器 SpringApplicationContext:容器用于加载配置文件,并提供获取 Bean 的方法 getBean()
  2. (应用)创建一个应用配置类 AppConfig: 用于标识 spring 框架需要扫描的包路径
  3. (应用)创建两个类 UserService,XxUtils:用于稍后交给 spring 框架来扫描,一个是 Bean 对象,一个普通的类,只有注解标记的类才会被解析
  4. 创建注解 @ComponentScan,@Component: 通过注解的方式来标记:哪些包需要被扫描,被扫描包目录下使用了 @Component 标记的类才就是 Bean 对象
  5. 通过类加载器获取注解标记的所有类对象,并准备将类对象转换为 Bean 对象的指定数据类型 BeanDefinition
  6. 此时,我们将 Bean 设计为两种类型: 单例 singleton原型 prototype. 因此创建一个注解 @Scope 用来标记这个对象是哪一种 Bean 类型
  7. 在扫描过程中,将所有的 Bean 都以 <beanName,beanDefinition>的键值对存入 beanDefinitionMap 中管理。
  8. 扫描完成后,为所有 bean 对象创建对应实例。这里:scope 作用域为单例的 Bean 首先在beanDefinitionMap中查找是否已创建,没有则创建,有则返回已创建的,scope 作用域为原型的 Bean 直接创建对应实例

  1. 依赖注入实现。所有的 Bean 已被扫描并存储在beanDefinitionMap中,并为所有的单例 Bean 创建了实例,所有的原型 Bean 仅仅是存储了其 Bean 数据结构beanDefinition
  2. 容器感知 beanNameAware: 对于某一个 Bean 本身(userService)而言,使用者是不知道关于容器的信息。实现 beanNameAware 容器感知
  3. Bean 初始化方式: 在 spring 源码中提供了两种 Bean 初始化方式,这里实现其中之一 initializingBean
  4. AOP 实现:通过 JAVA-JDK 动态代理实现,即实现 AOP 切面,实现位置位于 BeanPostProcessor.需要注意 代理是对 某一个具体对象的某种行为进行代理,所以必须被代理的对象必须至少实现一个接口

困难与挑战

在书写源码的过程中,遇到不清晰的知识点,记录在文件夹 source-ex

源码大赏

  1. spring 容器
    public SpringApplicationContext(Class<?> primarySource, Class<?> configClass) {
    
    
        this.configClass = configClass;
        // 扫描
        scanBeanDefinition(configClass);
        // AOP
        registerBeanPostProcessors();
        // 获取Bean
        preInstantiateSingletons();
    }

  1. 扫描 scanBeanDefinition
/**
     * 扫描.解析配置类
     * 过程:通过传入的配置信息 ComponentScan 获取扫描路径  --> 执行扫描 @Component
     *
     * @param configClass 配置类
     */
    private void scanBeanDefinition(Class<?> configClass) {
    
    

        // 1. 传递来的类,是都被扫描注解标记
        ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
        String scanPath = componentScanAnnotation.value();

        // 2. 获取扫扫描路径后,准备扫描。一个包下有许多的类,我们框架关心的是被指定注解标记的类(@Component),才会被扫描
        // 如何获取一个包下面的java类?使用类加载器

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL resource = classLoader.getResource("com/sourcecode/content/service");
        assert resource != null;
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
    
    
            for (File listFile : Objects.requireNonNull(file.listFiles())) {
    
    

                // 2.1 由于 classLoader.loadClass(quotePath) 需要获取的是 com.xxx.xxx这样的引用地址,所以需要转换一下
                String absolutePath = listFile.getAbsolutePath();
                if (absolutePath.endsWith(".class")) {
    
    
                    String quotePath = resolveClassAbsolutePath(absolutePath);
                    try {
    
    
                        Class<?> aClass = classLoader.loadClass(quotePath);

                        if (aClass.isAnnotationPresent(Component.class)) {
    
    

                            // 2.2 使用 @Component 注解装饰类:就表示希望将它交给Spring容器托管,它是一个bean对象
                            //  class  ---??--->  Bean
                            // 2.3 在将class转换为我们制定的Bean类型时,由于Bean有两种类型:单例和原型。需要使用单例模式来确保Bean对象的唯一性
                            // 因此,如何实现单例呢?
                            // 可以创建一个@Scope注解来标识它是单例还是原型Bean类型,同时创建一个Map来保存所有的Bean。
                            // Map {BeanName,BeanObject}  也就是常说的单例池

                            // 2.4 判断是单例Bean还是原型Bean
                            Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
                            String beanName = componentAnnotation.value();


                            if ("".equals(beanName)) {
    
    
                                beanName = Introspector.decapitalize(aClass.getSimpleName());
                            }

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

                            if (aClass.isAnnotationPresent(Scope.class)) {
    
    
                                Scope scopeAnnotation = aClass.getDeclaredAnnotation((Scope.class));
                                String scope = scopeAnnotation.value();
                                beanDefinition.setScope(scope);
                            } else {
    
    
                                beanDefinition.setScope("singleton");
                            }
                            // 存储Bean
                            beanDefinitionMap.put(beanName, beanDefinition);

                        }

                    } catch (ClassNotFoundException e) {
    
    
                        e.printStackTrace();
                    }
                }

            }
        }
    }
  1. 获取 Bean: preInstantiateSingletons
/**
     * 初始化:实例化所有的单例Bean
     */
    private void preInstantiateSingletons() {
    
    
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
    
    
            if (beanDefinition.isSingleton()) {
    
    
                getBean(beanName);
            }
        });
    }

    public Object getBean(String beanName) {
    
    
        Asset.notNull(beanName);
        if (!beanDefinitionMap.containsKey(beanName)) {
    
    
            throw new NullPointerException("没有找到bean:" + beanName);
        } else {
    
    
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

            if (beanDefinition.isSingleton()) {
    
    
                // 实现3级缓存或者使用最简单的一级缓存,只需在方法中 getSingleton 决定
                Object singletonObject = getSingleton(beanName, true);

                // 三级缓存中都没有,那么就只能 create
                if (singletonObject == null) {
    
    
                    singletonObject = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, singletonObject);
                    earlySingletonObjects.remove(beanName);
                    singletonFactories.remove(beanName);
                }

                return singletonObject;
            } else {
    
    
                // prototype.每次创建新对象
                return createBean(beanName, beanDefinition);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/win7583362/article/details/126949455