赞
踩
上次我们了解了Dubbo之ServiceBean ,dubbo把自定义的Service服务以ServiceBean的形式注册到SpringIOC容器中,由SpringIOC来管理dubbo服务的生命周期。
ServiceBean是服务提供方,今天我们来看下服务消费方是怎么加载的,核心入口类是ReferenceBean。
我们在配置文件加上<dubbo:reference /> 或者在成员变量上加上注解@Reference, 生成的对象是ReferenceBean,当然不完全是,其实生成的是一个代理类。
举个例子:
新建一个项目huhu-test,包含两个子模块,huhu-test-api、huhu-test-server
huhu-test-api,只有一个接口
public interface CarService {
String brand(String name);
}
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);
}
}
测试类
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;
}
}
注册中心,我使用的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);
}
}
启动dubbo
@Configuration
@EnableDubbo(scanBasePackages = "com.mytest.dubbo" )
public class DemoDubboConfig {
}
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,奥迪
一个简单的远程调用就完成了。那么ReferenceBean是怎么完成远程调用的?
在了解调用过程之前,我们先来看下,是怎么完成远程方法的创建的?核心方法就是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;
}
该方法会创建一个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; }
buildInvocationHandler方法,首先会创建ReferenceBeanInvocationHandler类,在执行代理类的方法时会执行该类的invoke方法。
接着会调用handler.init(),init方法
private void init() {
this.bean = referenceBean.get();
}
referenceBean.get()往下跟,会createProxy(map),然后会调用refprotocol.refer(interfaceClass, urls.get(0))
该方法会获取远程服务列表,然后和远程服务建立连接。调用链比较深,就不在本次分享里讲。
最终会创建一个com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker。当然在创建DubboInvoker之前会进行很多封装,并创建代理类。
本次分享结束,有问题欢迎指出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。