K8S下挖空Dubbo的一些思路--@Reference

通过@Reference的定义可以发现,这个注解可以作用在字段、方法和注解上

实际只需要实现作用于字段和方法上的情况,作用和@Autowired类似:填充字段和方法参数。可以直接将@Autowired作为元注解来使用

但是和@Autowired最大区别的是:@Reference作用的字段或方法参数是不会有实现类,需要在属性填充之前将代理类注册到spring容器中;当然可以不使用@Autowired作为元注解,参照dubbo或者spring的方式自己实现属性填充

实际可以使用的有两个:InstantiationAwareBeanPostProcessorBeanFactoryPostProcessor

@Reference定义

定义里的属性可以只做为占位符,大部分都是没有什么用处的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.alibaba.dubbo.config.annotation;

import org.springframework.beans.factory.annotation.Autowired;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Autowired
public @interface Reference {
......
}

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessorBeanPostProcessor的子接口,添加了bean实例化前回调、及属性填充之前的回调。有三个自己定义的方法

InstantiationAwareBeanPostProcessor通常是spring内部使用的接口,AutowiredAnnotationBeanPostProcessor就是用来处理@Autowired注解的

  • postProcessBeforeInstantiation:理论上这里bean还没有实例化。可以提供一个对象来替代内置的对象创建,提供后下面的后处理和属性注入自然都会跳过
  • postProcessAfterInstantiation:这里bean已经实例化。返回结果决定是否要执行下面的属性注入
  • postProcessProperties:AutowiredAnnotationBeanPostProcessor就是在postProcessProperties方法里查找需要注入的字段,并进行注入的

BeanFactoryPostProcessor

BeanFactoryPostProcessor是用来处理BeanFactory中bean定义的接口,可以获取所有的bean定义并修改

BeanFactoryPostProcessor要早于InstantiationAwareBeanPostProcessor,这里只是提供了在bean实例化之前修改bean定义的能力,一定不要在这里触发bean的初始化,否则可能会出现莫名其妙的bug

  • postProcessBeanFactory:提供ConfigurableListableBeanFactory可以从中获取所有bean名和bean定义

具体实现

虽然强调过不要在BeanFactoryPostProcessor里初始化bean了,但这里场景不同

  1. 初始化的是接口的代理类,里边不存在对spring的bean依赖,更不可能干扰整个IoC容器
  2. 只需要保证IoC容器里有实现类即可,具体的字段设置仍然希望借助@Autowired的能力,毕竟写的越多bug越多

所以这里使用还是使用了BeanFactoryPostProcessor,当然这里使用的是beanFactory.registerSingleton还是不推荐的,可以优化一下转成DefaultListableBeanFactory然后使用beanFactory.registerBeanDefinition

  1. doWithLocalFields是spring提供的查找类字段的方法
  2. doWithLocalMethods是spring提供的查找类方法的方法
  3. registerSingletonObject如果可以在容器里找到bean实例就跳过注册
  4. ReferenceInvokeHandler实现了InvocationHandler,就是jdk的代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
@Slf4j
public class DubboBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
final String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
final BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
final Class<?> beanClass = ClassCache.find(beanDefinition.getBeanClassName());
if (null != beanClass) {
ReflectionUtils.doWithLocalFields(beanClass, field -> {
AnnotationAttributes ann = findReferenceAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
return;
}
registerSingletonObject(beanFactory, field.getType());
}
});
ReflectionUtils.doWithLocalMethods(beanClass, method -> {
final Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
final AnnotationAttributes ann = findReferenceAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {
return;
}
if (method.getParameterCount() == 0) {
return;
}
final PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
if (null != pd) {
registerSingletonObject(beanFactory, pd.getPropertyType());
}
}
});
}
}
}

private AnnotationAttributes findReferenceAnnotation(AccessibleObject accessibleObject) {
if (accessibleObject.getAnnotations().length > 0) {
return AnnotatedElementUtils.getMergedAnnotationAttributes(accessibleObject, Reference.class);
}
return null;
}

private void registerSingletonObject(ConfigurableListableBeanFactory beanFactory, Class<?> fieldClass) {
if (null == fieldClass) {
return;
}
String[] beans = beanFactory.getBeanNamesForType(fieldClass);
if (beans.length > 0) {
return;
}

String fullName = fieldClass.getName();
if (!fieldClass.isInterface()) {
log.warn("Reference class: {} is not a interface, Unable to inject implementation class", fullName);
return;
}
Object proxy = Bottle.obtain(fullName);
if (null == proxy) {
proxy = Proxy.newProxyInstance(beanFactory.getBeanClassLoader(), new Class[]{fieldClass}, new ReferenceInvokeHandler(fieldClass));
Bottle.register(fullName, proxy);
beanFactory.registerSingleton(ServiceUtil.formatServiceName(fieldClass.getSimpleName()), proxy);
log.debug("Reference class: {} register success", fullName);
}
}
}

K8S下挖空Dubbo的一些思路--@Reference
https://back.pub/post/hh-code-replace-dubbo-1/
作者
Dash
发布于
2020年4月11日
许可协议