不使用他人jar包情況下優(yōu)雅的進(jìn)行dubbo調(diào)用詳解
1、正常dubbo調(diào)用流程
- 引入dubbo依賴
- 引入他人提供的clinet依賴包;
- 配置相同的注冊中心,使用@Reference注解注入對應(yīng)的service接口(注意是Reference是dubbo包下的,不是spring那個(gè))
2、如果想在不引用他人jar包的情況下如何調(diào)用呢?
dubbo泛化調(diào)用-dubbo原生支持的優(yōu)雅方法
使用場景:
- 消費(fèi)者不希望引入生產(chǎn)者提供的clinet依賴; 例如:消費(fèi)者是一個(gè)基礎(chǔ)服務(wù),需要調(diào)用很多生產(chǎn)者的dubbo方法,那他就要引入很多的jar包;
- 消費(fèi)者不使用java語言,而是使用其他的語言(例如:Python);
如何使用:
1.需要知道對方方法的全路徑名稱(interfaceName)
2.如果對方的dubbo有指定的版本號(version)和組(group)要指定一下,不然有很大可能會調(diào)用不通
3.要知道對方的注冊中心地址和連接方式(如果是在同一個(gè)zk注冊中心就更好了)
//1.獲取泛化對象
private GenericService getGenericService(String interfaceName, String version, String group) {
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
// set application
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setId(APPLICATION_ID);
applicationConfig.setName(APPLICATION_ID);
reference.setApplication(applicationConfig);
// 通過zookeeper連接
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(zkAddress);
registryConfig.setProtocol(ZOOKEEPER);
registryConfig.setCheck(false);
reference.setRegistry(registryConfig);
// set timeout
reference.setTimeout(syncForwardTimeout);
// set retry times
reference.setRetries(syncRetries);
// set check
reference.setCheck(false);
// set generic
reference.setGeneric(true);
// set interface version
if (version != null && version.length() != 0) {
reference.setVersion(version);
}
// set interface name
reference.setInterface(interfaceName);
// set service id
reference.setId(interfaceName);
// set dubbo protocol
reference.setProtocol(DUBBO);
//
if (group != null && group.length() != 0) {
reference.setGroup(group);
}
// 從zookeeper獲取緩存,從緩存中獲取泛化
return ReferenceConfigCache.getCache().get(reference);
}
//2.泛化調(diào)用入?yún)⑻幚?
```
private ResponseDataDto<R> invoke(GenericService genericService, UpDataReqDto upDataReqDto, String method) {
String[] paramTypes = new String[1];
Object[] paramValues = new Object[1];
int i = 0;
paramTypes[i] = upDataReqDto.getClass().getTypeName();
paramValues[i] = upDataReqDto;
Object object = genericService.$invoke(method, paramTypes, paramValues);
return JSON.parseObject(JSON.toJSONString(object), new TypeReference<ResponseDataDto<R>>(){});
}
```
實(shí)現(xiàn)原理:
- 泛化調(diào)用的實(shí)現(xiàn)主要涉及兩個(gè)filter
1. com.alibaba.dubbo.rpc.filter.GenericFilter 2. com.alibaba.dubbo.rpc.filter.GenericImplFilter
- 泛化調(diào)用的流程:
- 調(diào)用 <-> GenericImplFilter <-> 網(wǎng)絡(luò)(RPC) <-> GenericFilter <-> 服務(wù)實(shí)現(xiàn)
- 泛化調(diào)用的核心源碼:
GenericImplFilter:
```
//判斷是不是泛化調(diào)用
if (isCallingGenericImpl(generic, invocation)) {
RpcInvocation invocation2 = new RpcInvocation(invocation);
/**
* Mark this invocation as a generic impl call, this value will be removed automatically before passing on the wire.
* See {@link RpcUtils#sieveUnnecessaryAttachments(Invocation)}
*/
invocation2.put(GENERIC_IMPL_MARKER, true);
String methodName = invocation2.getMethodName();
Class<?>[] parameterTypes = invocation2.getParameterTypes();
Object[] arguments = invocation2.getArguments();
String[] types = new String[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
types[i] = ReflectUtils.getName(parameterTypes[i]);
}
Object[] args;
if (ProtocolUtils.isBeanGenericSerialization(generic)) {
args = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
args[i] = JavaBeanSerializeUtil.serialize(arguments[i], JavaBeanAccessor.METHOD);
}
} else {
args = PojoUtils.generalize(arguments);
}
if (RpcUtils.isReturnTypeFuture(invocation)) {
invocation2.setMethodName($INVOKE_ASYNC);
} else {
invocation2.setMethodName($INVOKE);
}
invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES);
invocation2.setParameterTypesDesc(GENERIC_PARAMETER_DESC);
invocation2.setArguments(new Object[]{methodName, types, args});
return invoker.invoke(invocation2);
}
// 普通服務(wù)進(jìn)行通用調(diào)用
else if (isMakingGenericCall(generic, invocation)) {
Object[] args = (Object[]) invocation.getArguments()[2];
if (ProtocolUtils.isJavaGenericSerialization(generic)) {
for (Object arg : args) {
if (byte[].class != arg.getClass()) {
error(generic, byte[].class.getName(), arg.getClass().getName());
}
}
} else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
for (Object arg : args) {
if (!(arg instanceof JavaBeanDescriptor)) {
error(generic, JavaBeanDescriptor.class.getName(), arg.getClass().getName());
}
}
}
invocation.setAttachment(
GENERIC_KEY, invoker.getUrl().getParameter(GENERIC_KEY));
}
GenericFilter:
if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
&& inv.getArguments() != null
&& inv.getArguments().length == 3
&& !GenericService.class.isAssignableFrom(invoker.getInterface())){
.......泛化調(diào)用處理邏輯......
}
3、總結(jié)
- 從源碼設(shè)計(jì)來看泛化調(diào)用提供了在沒有接口依賴的情況下進(jìn)行調(diào)用的解決方案;
- 從擴(kuò)展上來看泛化調(diào)用的侵入性不強(qiáng),可以很好的用于框架擴(kuò)展;
以上就是不使用他人jar包情況下優(yōu)雅的進(jìn)行dubbo調(diào)用詳解的詳細(xì)內(nèi)容,更多關(guān)于不引用jar包調(diào)用dubbo的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot中@ConfigurationProperties注解實(shí)現(xiàn)配置綁定的三種方法
這篇文章主要介紹了SpringBoot中@ConfigurationProperties注解實(shí)現(xiàn)配置綁定的三種方法,文章內(nèi)容介紹詳細(xì)需要的小伙伴可以參考一下2022-04-04
SpringBoot中Get請求和POST請求接收參數(shù)示例詳解
文章詳細(xì)介紹了SpringBoot中Get請求和POST請求的參數(shù)接收方式,包括方法形參接收參數(shù)、實(shí)體類接收參數(shù)、HttpServletRequest接收參數(shù)、@PathVariable接收參數(shù)、數(shù)組參數(shù)接收、集合參數(shù)接收、Map接收參數(shù)以及通過@RequestBody接收J(rèn)SON格式的參數(shù),感興趣的朋友一起看看吧2024-12-12
利用javaFX實(shí)現(xiàn)移動一個(gè)小球的示例代碼
這篇文章主要介紹了利用javaFX實(shí)現(xiàn)移動一個(gè)小球的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Spring實(shí)現(xiàn)動態(tài)修改時(shí)間參數(shù)并手動開啟關(guān)停操作
spring實(shí)現(xiàn)定時(shí)任務(wù)的方式有三種,分別是java自帶的timer類、spring task和quartz三種。本文只介紹spring自帶的task和第三方quartz,感興趣的朋友參考下吧2017-09-09
Java中DateTimeFormatter的使用方法和案例
在Java中,DateTimeFormatter類用于格式化和解析日期時(shí)間對象,它是日期時(shí)間格式化的強(qiáng)大而靈活的工具,本文將和大家一起探討Java中DateTimeFormatter的使用方法和案例,需要的朋友可以參考下2023-10-10

