手写Spring、了解Spring启动与Bean

手写Spring、了解Spring启动与Bean

更多请关注:https://t.zsxq.com/fhroW

手写模拟Spring启动时的操作,了解BeanDefinition和BeanPostProcessor.

创建Bean的大致步骤:

  • 执行构造方法
  • 得到普通对象
  • 进行依赖注入
  • 执行初始化前操作
  • 执行初始化操作
  • 执行初始化后操作

Spring启动后做了哪些事?

  • 扫描包
  • 创建单例Bean

扫描包

  • 从配置类中加载需要管理的Bean
  • 处理Bean,将所有Bean封装为BeanDefinition存入BeanDefinitionMap
  • 过滤单例Bean,创建单例Bean对象,存入单例池:SingletonMap
  • 过滤BeanPostProcessor,并创建对象存入beanPostProcessorList
  • 注意:BeanDefinitionMap中存了所有的Bean,单例池中只存了单例的Bean,BeanPostProcessorList中只存了实现了BeanPostProcessList的类

创建单例Bean

  • 遍历单例池
  • 进行依赖注入
  • 遍历BeanPostProcessorList,执行初始化之前的操作
  • 判断该类有无实现InitializingBean接口,实现则进行初始化操作
  • 遍历BeanPostProcessorList,执行初始化之后的操作
  • 判断改类有无实现Aware接口,有则进行回调操作

重要概念

BeanDefinition

Bean信息的封装类,其中包含Bean的类型、作用范围(单例、原型)、是否懒加载等
Spring启动时会把所有的Bean都封装为BeanDefinition

BeanPostProcessor

BeanPostProcessor是Spring提供的接口,如果类实现了该接口表示在所有bean创建时,会执行该类中的初始化前和初始化后操作。
这是Spring中非常重要的机制,Aop就是通过BeanPostProcessor实现的

需要注意的是,BeanPostProcessor对所有Bean生效,而初始化、回调这些接口只对实现了这些接口的Bean生效。

Aop是如何利用BeanPostProcessor机制实现切面的

通过BeanPostProcessor创建代理类,并将代理类返回,替换掉原先的普通对象,这样创建出的Bean就是代理对象。、

代码举例

手写Spring

ApplicationContenxt类

其中主要包含了两个对外的方法:

  • 构造方法:传入配置对象,获取扫描路径进行扫描
  • getBean方法,获取Bean
public class RxwsApplicationContext {

    private Class configClass;

    //存放所有BeanDefinition
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    //单例池
    private Map<String, Object> singletonObjects = new HashMap<>();
    //存放所有BenaPostProcessor
    private List<BeanPostProcessor> beanPostProcessorList = new LinkedList<>();

    public RxwsApplicationContext(Class configClass) throws Exception {
        this.configClass = configClass;
        //扫描Bean
        scanBean();
        //实例化Bean
        for (String key : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(key);
            if ("singleton".equals(beanDefinition.getScope())) {
                Object bean = createBean(key, beanDefinition);
                singletonObjects.put(key, bean);
            }
        }
    }
    
        /**
     * 获取Bean
     *
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) throws Exception {
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException("Bean不存在");
        }

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if ("singleton".equals(beanDefinition.getScope())) {
            //单例Bean从单例池中拿
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                //依赖注入的时候可能作为属性的bean还没有创建
                singletonBean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;
        } else {
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }
}

创建bean

大部分功能和机制都是在创建bean时进行处理的。 具体就是在创建后逐个去判断有没有实现某个接口,然后调用接口的方法

    private Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception {
        Class clazz = beanDefinition.getType();
        Object instance = null;
        instance = clazz.getConstructor().newInstance();
        //依赖注入
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(Autowire.class)) {
                field.setAccessible(true);
                field.set(instance, getBean(field.getName()));
            }
        }

        //初始化前的操作
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
        }

        //初始化  判断Bean是否实现了InitializingBean接口
        if (instance instanceof InitializingBean) {
            ((InitializingBean) instance).afterPropertiesSet();
        }

        //初始化后的操作
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
        }

        //检查回调,以BeanNameAware为例
        if (instance instanceof BeanNameAware) {
            ((BeanNameAware) instance).setBeanName(beanName);
        }
        return instance;
    }

扫描包

扫描包,扫描是从Target中拿到class文件,然后加载为类去操作的,扫描是就将Bean添加到上文提到的BeanDefinitionMap 、单例池 、 BeanProcessorList

    private void scanBean() throws Exception {
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = componentScanAnnotation.value();
            path = path.replace(".", "/");
            //通过类加载器从target中获取所有class文件
            ClassLoader appClassLoader = RxwsApplicationContext.class.getClassLoader();
            URL resource = appClassLoader.getResource(path);
            File files = new File(resource.getFile());

            if (files.isDirectory()) {
                for (File file : files.listFiles()) {
                    //D:\package\workspace\idea\mySpring\target\classes\rxws\UserService.class
                    String absolutePath = file.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("rxws"), absolutePath.indexOf(".class"));
                    //rxws.OrderService
                    absolutePath = absolutePath.replace("\\", ".");

                    //将文件加载进来成为类
                    Class<?> clazz = appClassLoader.loadClass(absolutePath);
                    //判断类有没有添加component注解,没有添加注解的不做处理
                    if (clazz.isAnnotationPresent(Component.class)) {
                        //如果类实现了BeanPostProcessor接口,则放入BeanPostProcessorList不放入单例池
                        if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                            //如果类实现了BeanPostProcessor接口,则放入beanProcessor集合中
                            BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();
                            beanPostProcessorList.add(beanPostProcessor);
                        } else {
                            BeanDefinition beanDefinition = new BeanDefinition();
                            String beanName = getBeanName(clazz);
                            //判断是单例还是原型
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //根据值判断是不是单例
                                Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                String scopeValue = scopeAnnotation.value();
                                beanDefinition.setScope(scopeValue);
                            } else {
                                beanDefinition.setScope("singleton");
                            }
                            //将bean存入map
                            beanDefinition.setType(clazz);
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    }
                }
            }
        }
    }

生成BeanName,Spring可以帮我们生成beanName,用户也可以自己指定

    private String getBeanName(Class clazz) throws Exception {
        Component componentAnnotation = (Component) clazz.getAnnotation(Component.class);
        String beanName = componentAnnotation.name();
        if ("".equals(beanName)) {
            //JDK提供的方法,根据类名首字母小写生成一个名称
            beanName = Introspector.decapitalize(clazz.getSimpleName());
        }
        return beanName;
    }

其他

  • 扫描包时应该也包含子包,上文有子包会报错
  • 创建Bean时会进行构造方法推断,上文直接使用无参构造
  • 属性依赖注入时是根据类型去找bean,上文是根据字段名去找bean
  • 依赖注入,即@Autowire实际上是通过BeanPostProcesor机制去实现的,上文是在创建Bean时实现的。

遇到的问题:

  • 当在BeanPostProcessor中使用了代理之后一定把代理对象复制给返回的Bean,不然给用户使用的还是普通对象,代理不会生效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值