文章目录
1 Dubbo和spring融合
1.1 Dubbo 命名空间解析
xml解析类的路径:org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
可以看到服务暴露的核心bean 是 ServiceBean , 调用引用的核心bean是ReferenceBean
1.2 spring容器支持
核心类 org.apache.dubbo.config.spring.extension.SpringExtensionFactory implements ExtensionFactory
public static void addApplicationContext(ApplicationContext context) {
CONTEXTS.add(context);
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).registerShutdownHook();
}
}
public static Set<ApplicationContext> getContexts() {
return CONTEXTS;
}
public <T> T getExtension(Class<T> type, String name) {
//SPI should be get from SpiExtensionFactory
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
return null;
}
for (ApplicationContext context : CONTEXTS) {
T bean = BeanFactoryUtils.getOptionalBean(context, name, type);
if (bean != null) {
return bean;
}
}
return null;
}
2 Dubbo扩展
##2.1 Java的SP实现方式
public interface IShout {
void shout();
}
public class Dog implements IShout{
public void shout() {
System.out.println("dog shout");
}
}
public class Cat implements IShout{
public void shout() {
System.out.println("cat shout");
}
}
META-INFO/services/com.jd.gloabal.spi.IShout
com.jd.gloabal.spi.Dog
com.jd.gloabal.spi.Cat
public class SPIMain {
public static void main(String[] args) {
ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);
for (IShout s : shouts) {
s.shout();
}
}
}
输出:
dog shout
cat shout
2.1 dubbo的SPI实现
spi 文件存储的路径再META-INFO\dubbo\internal目录下面,并且文件名为接口全路径名=接口的报名+接口名
每个spi文件里面的格式定义为 扩展名=具体的类名
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec
2.1.1 获取扩展实现方法
dubbo中最最核心的一个类 org.apache.dubbo.common.extension.ExtensionLoader
通过名字获取扩展点的实现
public T getExtension(String name) {
return getExtension(name, true);
}
private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name)
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
4 ExtensionLoader的产生,
ExtensionLoader getExtensionLoader(Class type) 就是为接口创建一个ExtensionLoader 然后缓存起来
和getAdaptiveExtension
3 Dubbo Transport 层相关
3.1 dubbo异步转同步实现方式
dubbo核心执行类
org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = calculateTimeout(invocation, methodName);
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else {
ExecutorService executor = getCallbackExecutor(getUrl(), inv);
CompletableFuture<AppResponse> appResponseFuture =
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result;
}
3.2 客户端请求到相应过程
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
return channel.request(request, timeout, executor);
}
底层调用的是下面的channel
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
// create request.
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
channel.send(req);
return future;
}
执行完毕则把该future 删除,同时设置返回值
```java
org.apache.dubbo.remoting.exchange.support.DefaultFuture
public static void received(Channel channel, Response response, boolean timeout) {
try {
DefaultFuture future = FUTURES.remove(response.getId());
if (future != null) {
Timeout t = future.timeoutCheckTask;
if (!timeout) {
t.cancel();
}
future.doReceived(response);
}
}
private void doReceived(Response res) {
if (res.getStatus() == Response.OK) {
this.complete(res.getResult());
}
判断如果是同步模式调用,则再线程中等待结果返回
org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult = invoker.invoke(invocation);
if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) {
asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
}
具体调用等待线程的方法
org.apache.dubbo.rpc.AsyncRpcResult
@Override
public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (executor != null && executor instanceof ThreadlessExecutor) {
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
threadlessExecutor.waitAndDrain();
}
return responseFuture.get(timeout, unit);
}
org.apache.dubbo.common.threadpool.ThreadlessExecutor
public void waitAndDrain() throws InterruptedException {
if (finished) {
return;
}
Runnable runnable = queue.take();
synchronized (lock) {
waiting = false;
runnable.run();
}
runnable = queue.poll();
while (runnable != null) {
try {
runnable.run();
} catch (Throwable t) {
logger.info(t);
}
runnable = queue.poll();
}
finished = true;
}
4 服务的暴露和引用
4.1 服务暴露:
暴露路径:
ServiceBean.onApplicationEvent
->ServiceConfig.export()
->doExportUrls() //里面有一个for循环,代表一个服务可以有多个通讯协议,例如tcp协议http协议,tcp是默认的协议
->loadRegistries(true) //从dubbo.properties 里面组装registry的url信息
->doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)
->exportLocal(URL url)
->proxyFactory.getInvoker(ref ,(Class) interfaceClass , local) dubbo会生成proxyFactory对象的扩展对象
->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName)
1 proxyFactory : 就是为了获取一个接口的代理类,例如获取远程接口的代理
它有两个方法,代表2个作用
a, getInvoker :针对server端,将服务对象,如DemoServiceImpl 包装成Invoker对象
b getProxy 针对client端,创建接口的代理对象,例如DemoService的接口
2 Wrapper 它类似spring的BeanWrapper ,他就是包装了一个接口或一个类,可以通过Wrapper对实力对象进行访问
3 Invoker : 它是一个可执行对象,能够根据方法的名称,参数得到对应的执行结果.
它里面有一个很重要的Result Invoke(Invocation invocation), invocation是包含了需要执行的方法和参数等重要信息,目前他只有2个实现类RpcInvocation mockInvocation
它有3中类型的Invoker
(1) 本地执行类的invoker
(2) 远程通信类的Invoker
(3) 多个远程执行类的invoker聚合成集群版的Invoker
--->protocol.export
-->Protocol$Adpative.export
-->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension("injvm")
-->extension.export(arg0)
-->ProtocolFilterWrapper.export
-->builInvokerChain //创建8个filter
-->injvmProtocol.export
->return new InjvmExport<T>(invoker ,invoker.getUrl().getServiceKey() , exporterMap)
-->目的: exporterMap.put(key ,this) //key = com.alibaba.dubbo.demo.DemoService,this=InjvmExporter
//如果配置的不是local则暴露为远程服务(配置为local, 则表示只暴露本地服务)
-->proxyFactory.getInvoker //原理和本地暴露一样都是为了获取一个Invoker对象
-->protoccol.export(invoker)
-->protocol$Adpative