程序员社区

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


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 流程

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

tag1:@EnableDubboConfig 注解

dubbo 源码解析2 + Spring 框架源码解读14插图1
dubbo 源码解析2 + Spring 框架源码解读14插图2
dubbo 源码解析2 + Spring 框架源码解读14插图3
dubbo 源码解析2 + Spring 框架源码解读14插图4
dubbo 源码解析2 + Spring 框架源码解读14插图5
dubbo 源码解析2 + Spring 框架源码解读14插图6
dubbo 源码解析2 + Spring 框架源码解读14插图7

tag2:@DubboComponentScan 注解

dubbo 源码解析2 + Spring 框架源码解读14插图8
dubbo 源码解析2 + Spring 框架源码解读14插图9

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

实现本地调用代码


FactoryBean 在 Spring 中实现的形式:

dubbo 源码解析2 + Spring 框架源码解读14插图10
dubbo 源码解析2 + Spring 框架源码解读14插图11
dubbo 源码解析2 + Spring 框架源码解读14插图12
赞(0) 打赏
未经允许不得转载:IDEA激活码 » dubbo 源码解析2 + Spring 框架源码解读14

一个分享Java & Python知识的社区