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 流程
tag1:@EnableDubboConfig 注解
tag2:@DubboComponentScan 注解
具体实现你应该也能想到,等我们写的时候再说吧
实现本地调用代码
FactoryBean 在 Spring 中实现的形式: