在Dubbo拦截器中拿到Invoker的引用对象
本文基于Dubbo 2.7.8。
当我们自定义Dubbo拦截器的时,有时候想要拿到代理对象(这里的代理对象是指Spring容器中的实际对象,可能已经被Cglib或Jdk代理),这里提供一种简单可行的方案。目前2.7.5及以上版本可用
先来看一下Dubbo服务导出的调用链:
//导出所有服务
private void exportServices() {
configManager.getServices().forEach(sc -> {
// TODO, compatible with ServiceConfig.export()
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
if (exportAsync) {
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future<?> future = executor.submit(() -> {
sc.export();
exportedServices.add(sc);
});
asyncExportingFutures.add(future);
} else {
sc.export();
exportedServices.add(sc);
}
});
}
//单个服务导出
public synchronized void export()
//是否需要导出
if (!shouldExport()) {
return;
}
checkAndUpdateSubConfigs();
doExport();
exported();
}
protected synchronized void doExport() {
if (exported) {
return;
}
exported = true;
if (StringUtils.isEmpty(path)) {
path = interfaceName;
}
doExportUrls();
}
private void doExportUrls() {
//这里是重点
ServiceRepository repository = ApplicationModel.getServiceRepository();
ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
repository.registerProvider(
getUniqueServiceName(),
ref,
serviceDescriptor,
this,
serviceMetadata
);
}
//注册提供者
public void registerProvider(String serviceKey,
Object serviceInstance,
ServiceDescriptor serviceModel,
ServiceConfigBase<?> serviceConfig,
ServiceMetadata serviceMetadata) {
ProviderModel providerModel = new ProviderModel(serviceKey, serviceInstance, serviceModel, serviceConfig,
serviceMetadata);
//key为serviceKey
providers.putIfAbsent(serviceKey, providerModel);
providersWithoutGroup.putIfAbsent(keyWithoutGroup(serviceKey), providerModel);
}
可以看到在Dubbo服务导出的时候会向ServiceRepository注册服务信息,而我们在Filter中可以通过Invocation的getTargetServiceUniqueName拿到serviceKey。
结果显而易见:
直接通过以下方式就可以拿到代理对象:
ProviderModel providerModel = ApplicationModel.getServiceRepository().lookupExportedService(invocation.getTargetServiceUniqueName());
System.out.println(providerModel.getServiceInstance().getClass());
怎么样是不是很简单,如果有其它需求从ServiceRepository中也可以很方便的拿到其他一些类和方法相关的信息。