美文网首页dubbo 源码解析
dubbo 源码解析2 + Spring 框架源码解读14

dubbo 源码解析2 + Spring 框架源码解读14

作者: 想54256 | 来源:发表于2020-05-19 14:57 被阅读0次

    title: dubbo 源码解析2 + Spring 框架源码解读14
    date: 2020/05/15 10:31


    本节内容

    为了更好的实现 RPC 框架,我们需要先实现一下 Spring 框架的 FactoryBean 和 SpringBoot 提供的 @ConfigurationProperties

    因为我不想解析配置文件,所以会带大家分析一下 @EnableDubbo 注解

    FactoryBean 实现

    我们先切回主分支,等我们写完再合并到其他分支

    /**
     * 注意 getObject() 返回的对象是不会依赖注入的
     */
    public interface FactoryBean<T> {
    
        /**
         * 返回此工厂管理的对象的实例(可能是共享的或独立的)
         */
        T getObject();
    
        /**
         * 返回此FactoryBean创建的对象的类型;如果事先未知,则返回{@code null}。
         *
         * @see ListableBeanFactory#getBeansOfType
         */
        Class<?> getObjectType();
    
        /**
         * 该工厂管理的对象是单例吗?也就是说,{@link #getObject()}是否总是返回同一对象(可以缓存的引用)
         */
        default boolean isSingleton() {
            return true;
        }
    
    }
    

    AbstractBeanFactory 的修改

    注:BeanFactory.FACTORY_BEAN_PREFIX 的值为 &

    /**
     * 根据名称获取对应的 bean (工厂方法模式)
     * <p>
     * 注:没有对原型做处理,如果2个对象都是原型,则会进入死循环从而堆栈溢出
     */
    @Override
    public Object getBean(String name) {
    
        // 先从一级缓存中获取
        // 如果一级缓存中没有,则从二级缓存中获取(防止循环引用)
        // 如果二级缓存中没有,则获取 bd 创建
        //      1. & 开头,将 name 删除 &;获取 FB 对象,判断是否是 FB 类型,不是报错,清除2级缓存;是否单例;然后返回
        //      2. 非 & 开头,直接获取,如果是 FB 类型,调用它的 getObj 方法,之后加入一级缓存
    
    
        // 先从一级缓存中获取
        if (sharedInstanceCache.containsKey(name)) {
            return sharedInstanceCache.get(name);
        }
    
        // 如果一级缓存中没有,则从二级缓存中获取(防止循环引用)
        if (earlySingletonObjects.containsKey(name)) {
            return earlySingletonObjects.get(name);
        }
    
        // 如果二级缓存中没有,则获取 bd 创建
        // 如果是 FactoryBean 类型
        if (this.isFactoryBean(name)) {
    
            // 不带 & 的 beanName
            String beanName = name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) ? name.substring(1) : name;
    
            BeanDefinition bd = this.getBeanDefinition(beanName);
            if (ObjectUtil.isNotNull(bd)) {
                Object bean = this.createBean(bd);
    
                // 如果不是 FB 类型则报错
                if (!(bean instanceof FactoryBean)) {
                    // 清除二级缓存
                    earlySingletonObjects.remove(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
                    // 抛出异常
                    throw new RuntimeException("获取的 bean 不是 FactoryBean 类型,请不要使用 & 开头作为 BeanName");
                } else {
                    // 判断是否是单例,如果是则将 FB 对象加入一级缓存
                    if (bd.getScope() == BeanDefinition.ScopeEnum.SINGLETON) {
                        sharedInstanceCache.put(BeanFactory.FACTORY_BEAN_PREFIX + bd.getName(), bean);
                    }
    
                    // 如果 name 是以 & 开头,则直接返回对象
                    if (name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
                        return bean;
                    } else {
                        // 否则,调用它的 getObject() 方法获取对象,如果单例加入一级缓存
                        FactoryBean<?> fb = (FactoryBean<?>) bean;
                        Object obj = fb.getObject();
                        if (fb.isSingleton()) {
                            sharedInstanceCache.put(beanName, obj);
                        }
                        return obj;
                    }
                }
            }
        } else {
            // 否则,是普通对象
            BeanDefinition bd = this.getBeanDefinition(name);
            if (ObjectUtil.isNotNull(bd)) {
                Object bean = this.createBean(bd);
                // 判断是否是单例,如果是则加入一级缓存中
                if (bd.getScope() == BeanDefinition.ScopeEnum.SINGLETON) {
                    sharedInstanceCache.put(bd.getName(), bean);
                }
                return bean;
            }
        }
    
        // 如果 bd 为空,而且没有父 bf,则抛出异常
        if (ObjectUtil.isNull(parentBeanFactory)) {
            throw new RuntimeException("获取的bean不存在!");
        }
    
        // 从父 bf 中获取
        return parentBeanFactory.getBean(name);
    }
    
    private boolean isFactoryBean(String beanName) {
    
        // 判断是否以 & 开头
        if (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
            return true;
        }
    
        // 判断类型是否是 FB 的子类
        BeanDefinition bd = this.getBeanDefinition(beanName);
    
        Class<?> beanType;
        String className = bd.getClassName();
        if (ObjectUtil.isNotEmpty(className)) {
            beanType = ReflectUtils.getType(className);
        } else {
            beanType = this.factoryMethodReturnType(bd);
        }
    
        return FactoryBean.class.isAssignableFrom(beanType);
    }
    
    protected Class<?> factoryMethodReturnType(BeanDefinition bd) {
        String factoryBeanName = bd.getFactoryBean();
        String factoryMethod = bd.getFactoryMethod();
    
        BeanDefinition factoryBD = this.getBeanDefinition(factoryBeanName);
        String factoryClassName = factoryBD.getClassName();
        if (ObjectUtil.isNotEmpty(factoryBD)) {
            Method method = ClassUtil.getDeclaredMethod(ReflectUtils.getType(factoryClassName), factoryMethod);
            return method.getReturnType();
        } else {
            return this.factoryMethodReturnType(bd);
        }
    }
    
    /**
        * 根据 bd 创建对象
        * <p>
        * 1)创建bean 日后需要对有参构造进行扩展
        * 2)注入属性(Spring 源码中 2 是在 3456 的后面)
        * 3)调用部分 Aware 的方法
        * 4)后置处理器的前置方法
        * 5)执行初始化操作
        * 6)后置处理器的后置方法
        * 7)注册销毁的处理
        */
    private Object createBean(BeanDefinition beanDefinition) {
    
        // 1、创建 bean
        BeanWrapper beanWrapper = this.createBeanInstance(beanDefinition);
    
        // 1.1 将还没有注入属性的 bean 放入二级缓存中
        if (beanDefinition.getScope() == BeanDefinition.ScopeEnum.SINGLETON) {
    
            // 需要判断这个对象是不是 FB,如果是,加入二级缓存的时候要加 & 符号
            String name = beanDefinition.getName();
            if (isFactoryBean(name)) {
                name = BeanFactory.FACTORY_BEAN_PREFIX + name;
            }
            earlySingletonObjects.put(name, beanWrapper.getWrappedInstance());
        }
        ...
    
    

    ListableBeanFactoryImpl 类的修改

    /**
     * 根据类型获取容器中所有这个类型的名字
     */
    @Override
    public String[] getBeanDefinitionNames(Class<?> type) {
        // Spring 5.0 为了效率加了个缓存
    
        List<String> matches = new ArrayList<>();
    
        beanDefinitionMap.forEach((beanName, bd) -> {
            Class<?> beanType;
    
            String className = bd.getClassName();
            if (ObjectUtil.isNotEmpty(className)) {
                beanType = ReflectUtils.getType(className);
            } else {
                beanType = super.factoryMethodReturnType(bd);
            }
    
            // 如果类型是 BeanFactory 类型,则更新 beanType
            if (FactoryBean.class.isAssignableFrom(beanType)) {
                Object fb = this.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
                beanType = ((FactoryBean<?>)fb).getObjectType();
            }
    
            if (type.isAssignableFrom(beanType)) {
                matches.add(beanName);
            }
        });
        return matches.toArray(new String[0]);
    }
    

    测试见提交的 14.0 中

    @ConfigurationProperties 注解的实现

    SpringBoot 的代码太难看了,我自己随便实现一下把,SpringBoot @ConfigurationProperties 注解

    public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, EnvironmentAware {
    
        private Environment environment;
    
        @Override
        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
    
        /**
         * 注:只支持基本类型
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            Class<?> beanClass = bean.getClass();
            ConfigurationProperties configurationProperties = AnnotationUtil.getAnnotation(beanClass, ConfigurationProperties.class);
            if (configurationProperties != null) {
                String prefix = configurationProperties.value();
                Map<String, String> propertyByPrefix = environment.getPropertyByPrefix(prefix);
                propertyByPrefix.forEach((fieldName, fieldValue) -> {
                    Field field = ReflectUtil.getField(beanClass, fieldName);
                    if (field != null) {
                        Class<?> type = field.getType();
                        ReflectUtil.setFieldValue(bean, field, ReflectUtils.string2BasicType(fieldValue, type));
                    }
                });
            }
    
            return bean;
        }
    }
    

    还有两个注解,就不贴了。

    @EnableDubbo 流程

    image

    tag1:@EnableDubboConfig 注解

    image image image image image image image

    tag2:@DubboComponentScan 注解

    image image

    具体实现你应该也能想到,等我们写的时候再说吧

    实现本地调用代码


    FactoryBean 在 Spring 中实现的形式:

    image image image

    相关文章

      网友评论

        本文标题:dubbo 源码解析2 + Spring 框架源码解读14

        本文链接:https://www.haomeiwen.com/subject/efjbohtx.html