动态代理系列(四)RPC中动态代理
看过上一讲动态代理换种玩法,我们知道通过变形的动态代理,可以不需要目标类,就能生成代理类。
这种技术,在我们今天的RPC框架中可以说被广泛的使用。
RPC调用.jpg
下面我就通过我写的一个简单的RPC组件 来介绍它是如何实现。(注意:当前版本可能为快照版本,代码在dev分支,未合并到master分支)
Spring的Autowired装配
在Spring中,我们可以通过Autowired方式进行对象的装配注入,也就是说字段要被注入,需要被注解标记。那么我们可以猜想,Spring一定有一段逻辑,来操作这个注入装配的过程。
并且,Spring为了好的可扩展性,以插件化的方式对装配Bean的过程进行补充,这些插件就叫后处理器。而对Autowired进行组装的后处理器就是:AutowiredAnnotationBeanPostProcessor,而具体的实现方法就是postProcessPropertyValues()。有兴趣的可以自行阅读。
RPC调用
我们知道本地调用肯定是通过对象完成,仅仅接口,如果没有实例对象,是要报空指针的,但是RPC是远程的过程调用,是调用远程的对象,远程的方法,本地是没有实例对象存在的,那不就矛盾了吗?
毫无疑问,调用,肯定就有对象,只不过,这个对象我们没有手工编码,看到这里,可能有些同学已经想到什么了。没错,就是上节介绍的动态代理为接口伪装出一个实现类。
对象可以通过动态代理生成,那么如何把生成的对象如同Autowired注解标记的字段一样进行装配呢?
实现装配
既然我们知道了Autowired注解装配的原理—通过后处理器完成。那么最简单的方式,我们就仿照写一个注解,一个处理器不就成了。
注解
我们写的注解是Reference,在SpringBean中被使用,看下面代码:
@RestController
public class DemoController {
@Reference(contract = IntfDemo.class, implCode = "abc")
private IntfDemo intfDemo;
@RequestMapping(path = "f1")
public String f1() {
return intfDemo.name();
}
}
装配处理器
写一个后处理,来处理被Reference注解标记的字段,具体实现如下:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
/**
* 处理SpringBean的{@link Reference} 属性的注入
*
* @author: guanjie
*/
@Component
@Slf4j
public class ReferenceBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, final Object bean, final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
FieldUtils.writeField(field, bean, ServerProxy.getProxy(field), true);
}
}, new ReflectionUtils.FieldFilter() {
@Override
public boolean matches(Field field) {
return field.isAnnotationPresent(Reference.class);
}
});
return pvs;
}
}
看上面功能代码,不超过20行,就把这个功能完成了,而Spring会自动发现这个处理器,并在装配阶段对每个Bean使用。
ServerProxy.getProxy(field)和上节中生成代理类的方式几乎一样,只不过把处理逻辑换成了IO通信而已。
原理懂了其实还是挺简单的,想了解的更多,可以拉下代码研究,欢迎感兴趣的同学一起来进行代码的维护和后续的补充。