当前位置: 首页 > article >正文

手写模拟Spring的基本功能

文章目录

  • 1. Spring的基本功能
  • 2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象
  • 3. BeanDefinition扫描
  • 4. Bean的生命周期
  • 5. 单例Bean与多例Bean
  • 6. 依赖注入
  • 7. AOP
  • 8. Aware 回调
  • 9. 初始化
  • 10. BeanPostProcessor
  • 附录:

1. Spring的基本功能

在这里插入图片描述

2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象

// 自定义的 IOC 容器对象
GyhApplicationContext gyhApplicationContext =
                new GyhApplicationContext(AppConfig.class);

3. BeanDefinition扫描

  • 对于基于注解的方式,会在构造方法中扫描 @ConponentScan 的 value 值对应其下的所有类对应的 .class 文件(存在于 out 文件夹下)
  • 将 扫描到的bean信息(Class, scope)封装至 BeanDefinition 对象中并由 一个 Map (beanDefinitionMap) 保存 beanName ---> BeanDefinition

4. Bean的生命周期

在这里插入图片描述

createBean 中:

  1. 利用 Bean 的空构造器通过反射创建
  2. 设置对象属性(伴随着依赖注入)
  3. 执行前置处理器
  4. 执行初始化方法
  5. 执行后置处理器
  6. 调用使用
  7. 执行 destory 方法

5. 单例Bean与多例Bean

  • 对于 单例Bean 是在初始化容器时(扫描过程中)创建并由 一个 Map(singletonObjects)管理 beanName —> beanInstance
  • 对于 多例Bean 是在 getBean() 方法中实时创建的

6. 依赖注入

  • 在 createBean 方法中,扫描所有 bean 被 @Autowire 标注的属性为其注入容器中的 bean
  • 若当前容器中还没有所依赖bean,则会创建该bean,然后再注入

7. AOP

  • spring是基于 动态代理
  • 初始化后,通过动态代理生成实现了指定接口的代理类
  • 使用了AOP对应的 bean 会被代理类的对象所替换

8. Aware 回调

  • 对应自定义的bean的类实现了Spring中指定的 Aware接口。可以在创建 bean 的过程中被检索到,并在定制的顺序中执行 Aware接口中定义的方法(即调用bean中实现的Aware接口的方法)

9. 初始化

  • 是spring的Aware接口中的一种,spring会检索实现了 InitializationBean 接口的 Bean。在创建这些bean是会调用其实现的 afterPropertiesSet 方法

10. BeanPostProcessor

  • 后置处理器,也是Aware回调接口中的一种,其定义的前置与后置方法会被用在所有bean的创建过程中

附录:

GyhApplicationContext

package com.gyh.spring;

import com.gyh.service.UserService;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Gao YongHao
 * @version 1.0
 * 模拟Spring的javaConfig的容器启动方式
 */

public class GyhApplicationContext {
    private Class<?> configClass;

    // 用于保存Bean对象的信息(class 对象, 作用域信息)
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
            new ConcurrentHashMap<>();

    // 用于保存单例的对象
    private ConcurrentHashMap<String, Object> singletonObjects =
            new ConcurrentHashMap<>();

    // 用于保存 BeanPostProcessor 的集合
    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    public GyhApplicationContext(Class<?> configClass) {
        this.configClass = configClass;

        // 扫描,单例的对象被直接创建,多例的对象在使用时创建
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan annotation = configClass.getAnnotation(ComponentScan.class);
            String packagePath = annotation.value(); // 扫描路径 "com.gyh.service"

            packagePath = packagePath.replace(".", "/");

            // 在 out 文件夹中定位 .class 文件的路径
            ClassLoader classLoader = GyhApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(packagePath);
            File file = new File(resource.getFile());
//            System.out.println(file);
            // 如果是文件夹
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f : files) {
                    String absolutePath = f.getAbsolutePath();
                    // 筛选出 .class 结尾的字节码文件
                    if (absolutePath.endsWith(".class")) {
                        String loadClassPath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                        loadClassPath = loadClassPath.replace("\\", ".");
                        // loadClassPath == "com\gyh\service\UserService"
//                        System.out.println(loadClassPath);
                        try {
                            // 利用类加载器加载指定文件夹下的 .class 文件
                            Class<?> aClass = classLoader.loadClass(loadClassPath);
                            // 查看是否有标注 Bean 对应的的注解
                            if (aClass.isAnnotationPresent(Component.class)) {
                                // 扫描出实现了 BeanPostProcessor 的 bean,将其实例化对象放置于 集合 中
                                if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
                                    beanPostProcessors.add((BeanPostProcessor) aClass.newInstance());
                                }

                                // 设置的Bean名称(若为""或null)则设置为首字母小写的类名
                                String beanName = aClass.getAnnotation(Component.class).value();
                                if ("".equals(beanName)) {
                                    beanName = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);
                                }

                                // 创建保存Bean信息的对象
                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setType(aClass); // 该对象类型

                                if (aClass.isAnnotationPresent(Scope.class)) {
                                    Scope annotation1 = aClass.getAnnotation(Scope.class);
                                    String value = annotation1.value();
                                    beanDefinition.setScope(value);
                                } else { // 默认是单例的
                                    beanDefinition.setScope("Singleton");
                                }

                                // 放置于 beanDefinitionMap 中管理
                                beanDefinitionMap.put(beanName, beanDefinition);
                            }

                            // 填充单例对象
                            for (Map.Entry<String, BeanDefinition> s : beanDefinitionMap.entrySet()) {
                                BeanDefinition value = s.getValue();
                                if (value.getScope().equals("Singleton")) {
                                    // 存有依赖注入的单例对象生成
                                    singletonObjects.put(s.getKey(), createBean(s.getKey(), value));
                                }
                            }

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

                    }
                }
            }
        }
    }

    /**
     * 创建Bean对象,
     *
     * @param beanName       bean 对象名称
     * @param beanDefinition bean 对象的信息
     * @return
     */
    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> type = beanDefinition.getType();
        Object o = null;
        try {
            o = type.getConstructor().newInstance();

            // 依赖注入
            // 遍历属性对属性进行依赖注入
            for (Field f : type.getDeclaredFields()) {
                if (f.isAnnotationPresent(Autowired.class)) {
                    f.setAccessible(true); // 关闭访问权限
                    // 将容器中管理的bean注入到该属性中(可能先于当前类创建,也可能后于当前类创建)
                    f.set(o, getBean(beanName, type));
                }
            }

            // 回调机制,查看当前的Bean是否实现了指定的接口
            // 如果实现则执行相关方法(BeanPostProcessor即是如此实现)
            if (o instanceof BeanNameAware) {
                ((BeanNameAware) o).setBeanName(beanName);
            }
            for(BeanPostProcessor b:beanPostProcessors){
                b.beforePostProcess(beanName, o);
            }

            // 初始化也使用回调实现

            // 基于AOP会在后置处理器中创建 bean 的动态代理对象,并封装切面逻辑
            for(BeanPostProcessor b:beanPostProcessors){
                b.afterPostProcess(beanName, o);
            }


        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return o;
    }

    /**
     * 用于返回 Bean 对象的方法
     *
     * @param beanName Bean 的名称
     * @param clazz    Bean 对应的 Class 对象
     * @param <T>
     * @return
     */
    public <T> T getBean(String beanName, Class<T> clazz) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new NullPointerException();
        } else {
            String scope = beanDefinition.getScope();
            if (scope.equals("Singleton")) {
                // 从单例池中获取对象
                Object o = singletonObjects.get(beanName);

                if (o == null) { // 对应依赖注入时可能会用到
                    o = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, o); // 放入单例池中
                }
                return (T) o;

            } else { // 多例则实时创建
                Object o = null;
                try {
                    o = beanDefinition.getType().newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                return (T) o;
            }
        }
    }
}


http://www.kler.cn/news/358051.html

相关文章:

  • 小白投资理财 - 解读利润指标
  • 【Spring】获取Cookie和Session(@CookieValue()和@SessionAttribute())
  • 剖析DNS劫持攻击原理及其防御措施
  • RAG流程的实现与改进
  • 微前端 Spa qiankun
  • Java项目-基于Springboot的高校党务系统项目(源码+说明).zip
  • MYSQL 表对表快速迁移-直接拷贝表空间文件.ibd进行迁移
  • ansible————ansible的文件管理
  • rv1126-rv1109-linux-进程启动
  • 苍穹外卖学习笔记(二十四)
  • 分布式混沌工程工具(ChaosBlade)
  • 10-Docker安装Redis
  • C语言实践中的补充知识 Ⅱ
  • Python爬虫:获取去哪儿网目的地下的评论数据
  • 一图解千言,了解常见的流程图类型及其作用
  • 个人健康系统|个人健康数据管理系统|基于小程序+java的个人健康数据管理系统设计与实现(源码+数据库+文档)
  • Windows API 一 ----起步
  • 深入理解 KMP 算法
  • 数据仓库-数仓分层建设
  • LeetCode 209 - 长度最小的子数组(滑动窗口法)