当前位置:   article > 正文

Dubbo之ReferenceBean

referencebean

上次我们了解了Dubbo之ServiceBeandubbo把自定义的Service服务以ServiceBean的形式注册到SpringIOC容器中,由SpringIOC来管理dubbo服务的生命周期。
ServiceBean是服务提供方,今天我们来看下服务消费方是怎么加载的,核心入口类是ReferenceBean。

什么是ReferenceBean

我们在配置文件加上<dubbo:reference /> 或者在成员变量上加上注解@Reference, 生成的对象是ReferenceBean,当然不完全是,其实生成的是一个代理类。
举个例子:
新建一个项目huhu-test,包含两个子模块,huhu-test-api、huhu-test-server
huhu-test-api,只有一个接口

public interface CarService {

    String brand(String name);
}
  • 1
  • 2
  • 3
  • 4

huhu-test-server,是一个Springboot项目
启动类

// 激活dubbo
@EnableDubbo(scanBasePackages = "com.huhu.huhutest.dubbo")
@SpringBootApplication
public class HuhuTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(HuhuTestApplication.class, args);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

测试类

import com.alibaba.dubbo.config.annotation.Service;
import com.huhu.huhutest.dubbo.api.CarService;

@Service
public class CarServiceImpl implements CarService {

    public String brand(String name) {
        return "hello," + name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注册中心,我使用的zookeeper,这个配置过程忽略。
新建一个MyTest项目
新建一个DemoService,引用CarService

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.huhu.huhutest.dubbo.api.CarService;

@Service
public class DemoServiceImpl implements DemoService {

    @Reference
    private CarService carService;

    @Override
    public String demo(String b) {
        return carService.brand(b);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

启动dubbo

@Configuration
@EnableDubbo(scanBasePackages = "com.mytest.dubbo" )
public class DemoDubboConfig {
}
  • 1
  • 2
  • 3
  • 4

main方法

public static void main(String[] args) throws IOException {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoDubboConfig.class);
    context.start();
    DemoService demoService = context.getBean(DemoService.class);
    System.out.println(demoService.demo("奥迪"));
}

输出:
hello,奥迪
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

一个简单的远程调用就完成了。那么ReferenceBean是怎么完成远程调用的?

ReferenceBean.get()

在了解调用过程之前,我们先来看下,是怎么完成远程方法的创建的?核心方法就是ReferenceBean.get()。
我们先看下什么时候会调用ReferenceBean.get()。
dubbo提供com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor,SpringIOC容器在给属性赋值时会判断该属性有没有注解@Reference。
会调用doGetInjectedBean方法:

@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
                                   InjectionMetadata.InjectedElement injectedElement) throws Exception {

    String referencedBeanName = buildReferencedBeanName(reference, injectedType);

    ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());

    cacheInjectedReferenceBean(referenceBean, injectedElement);

    Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);

    return proxy;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

该方法会创建一个ReferenceBean,injectedType是我们要引入的远程服务CarService。然后会创建一个代理类,方法buildProxy:

private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) {
    InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
    Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
    return proxy;
}

private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {

    ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);

    if (handler == null) {
        handler = new ReferenceBeanInvocationHandler(referenceBean);
    }

    if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ?
        // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
        localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
    } else {
        // Remote Reference Bean should initialize immediately
        handler.init();
    }

    return handler;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

buildInvocationHandler方法,首先会创建ReferenceBeanInvocationHandler类,在执行代理类的方法时会执行该类的invoke方法。
接着会调用handler.init(),init方法

private void init() {
    this.bean = referenceBean.get();
}
  • 1
  • 2
  • 3

referenceBean.get()往下跟,会createProxy(map),然后会调用refprotocol.refer(interfaceClass, urls.get(0))
该方法会获取远程服务列表,然后和远程服务建立连接。调用链比较深,就不在本次分享里讲。
最终会创建一个com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker。当然在创建DubboInvoker之前会进行很多封装,并创建代理类。

本次分享结束,有问题欢迎指出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/165900
推荐阅读
相关标签
  

闽ICP备14008679号