动态代理系列(四)RPC中动态代理

看过上一讲动态代理换种玩法,我们知道通过变形的动态代理,可以不需要目标类,就能生成代理类。

这种技术,在我们今天的RPC框架中可以说被广泛的使用。


动态代理系列(四)RPC中动态代理_第1张图片
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通信而已。

原理懂了其实还是挺简单的,想了解的更多,可以拉下代码研究,欢迎感兴趣的同学一起来进行代码的维护和后续的补充。

你可能感兴趣的:(动态代理系列(四)RPC中动态代理)