服务提供端主要是利用ServiceAnnotationPostProcessor对@DubboService注解的解析。
DubboClassPathBeanDefinitionScanner扫描指定路径下dubbo涉及的bean。如果@EnableDubbo没有显式指定路径,则默认为启动类所在的包路径,此时意味着Dubbo需要遍历应用中所有类是否为候选类,所以显示指定路径可以提升应用启动速率。
Dubbo中目标接口的多个实现类必须通过version版本号区别。针对每个候选类在Spring IOC中存在两种形式,一种是beanName + Class属性(候选类真实Class类型),另一种是 beanName:version + Class属性为ServiceBean。最后一种形式也是后置处理器ServiceAnnotationPostProcessor类涉及的核心功能。
public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPostProcessor {
private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
DubboService.class,
// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service
Service.class,
// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue : https://github.com/apache/dubbo/issues/4330
com.alibaba.dubbo.config.annotation.Service.class
);
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
scaned = true;
...
// resourceLoader:AnnotationConfigServletWebApplicationContext
DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
// 通过 已知注解类型 对候选类进行过滤是否满足条件
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
}
ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
// 通过 对候选类进行过滤 判断是否需要排除 候选类
scanner.addExcludeFilter(scanExcludeFilter);
for (String packageToScan : packagesToScan) {
...
// 扫描 packagesToScan路径下所有候选类,并且利用 AnnotationTypeFilter 过滤得到 当前注解所关注的候选类
// 候选类在IOC容器中正常普通注册【不需要代理】
scanner.scan(packageToScan);
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
// 将候选类包装为 ServiceBean 类型,以便代理处理
processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
servicePackagesHolder.addScannedPackage(packageToScan);
}
}
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
// 获取目标类存在的注解 @DubboService
Annotation service = findServiceAnnotation(beanClass);
// The attributes of @Service annotation
Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
// 目标类实现的接口全限定名
String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
// annotatedServiceBeanName:目标类原始IOC种bean name
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// ServiceBean Bean name
// beanName:ServiceBean:serviceInterface:version:group
//例如:ServiceBean:common.service.CountryService:1.0
String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);
// 将目标类的 @DubboService 注解相关属性 抽象为一个类 ~ ServiceBean
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);
// IOC容器中创建 beanName 对应的实例,这个实例其实就是 ServiceBean
registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}
}
1.ServiceBean之本地注册服务
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exception {
if (StringUtils.isEmpty(getPath())) {
if (StringUtils.isNotEmpty(getInterface())) {
setPath(getInterface());
}
}
//register service bean
//从IOC容器中获取ModuleModel
ModuleModel moduleModel = DubboBeanUtils.getModuleModel(applicationContext);
// ModuleConfigManager
moduleModel.getConfigManager().addService(this);
moduleModel.getDeployer().setPending();
}
}
通过上述分析得知在IOC容器中存在两种类型的候选类,一种是候选类真实类型,另一种即为需要代理处理的ServiceBean。
在Spring刷新容器过程中会遍历注册表中全部候选类,其中包括InitializingBean类型的ServiceBean。在接口核心方法内部将候选类注册为dubbo服务,即dubbo:service。
2.DubboDeployApplicationListener实现服务发布
注册监听器DubboDeployApplicationListener,并由此监听器发送ContextRefreshedEvent事件。
public class DubboDeployApplicationListener implements ApplicationListener<ApplicationContextEvent>, ApplicationContextAware, Ordered {
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
// DefaultModuleDeployer
ModuleDeployer deployer = moduleModel.getDeployer();
Future future = deployer.start();
future.get();
}
}
public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> implements ModuleDeployer {
// DefaultApplicationDeployer
private ApplicationDeployer applicationDeployer;
@Override
public synchronized Future start() throws IllegalStateException {
...
// 不管是 DefaultApplicationDeployer 还是DefaultModuleDeployer的initialize方法,都是处理相关配置文件
// 其功能等价于监听器 DubboConfigApplicationListener
applicationDeployer.initialize();
initialize();
// 真正触发 服务注册功能
exportServices();
...
return startFuture;
}
private void exportServices() {
// 从ModuleConfigManager遍历每一个ServiceBean,即dubbo.service
for (ServiceConfigBase sc : configManager.getServices()) {
exportServiceInternal(sc);
}
}
private void exportServiceInternal(ServiceConfigBase sc) {
ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
...
if (sc.isExported()) {return;}
...
sc.export();
}
}
public class ServiceConfig<T> extends ServiceConfigBase<T> {
// 服务接口
protected Class<?> interfaceClass;
// 服务接口的实现类
protected T ref;
private Protocol protocolSPI;
private ProxyFactory proxyFactory;
private void exportUrl(URL url, List<URL> registryURLs) {
String scope = url.getParameter(SCOPE_KEY);
url = exportRemote(url, registryURLs);
if (!isGeneric(generic) && !getScopeModel().isInternal()) {
// 利用zookeeper 客户端注册服务
MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel());
}
this.urls.add(url);
}
private URL exportRemote(URL url, List<URL> registryURLs) {
// 服务接口 javassist 代理
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
if (withMetaData) {
invoker = new DelegateProviderMetaDataInvoker(invoker, this);
}
Exporter<?> exporter = protocolSPI.export(invoker);
exporters.add(exporter);
}
}
- 通过ProxyFactory创建Invoker。
- 利用NettyTransporter启动服务提供端提供rpc功能的NettyServer。监听端口20880注册的客户端连接Socket。
- 利用Protocol将服务提供方的服务export出去。
发布服务过程中涉及两种类型的Protocol链:
- ServiceConfig:ProtocolSerializationWrapper->ProtocolFilterWrapper->ProtocolListenerWrapper->RegistryProtocol。
- RegistryProtocol内部生成本地Exportor:ProtocolSerializationWrapper->ProtocolFilterWrapper->ProtocolListenerWrapper->QosProtocolWrapper->DubboProtocol
2.1.Invoker的创建
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,Class<?>[] parameterTypes,Object[] arguments){
// 利用反射调用目标接口实现类的目标方法
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
- 对目标接口的实现类proxy做javaassit代理。
- javaassit代理的类被包装为Wrapper,最终返回Invoker为AbstractProxyInvoker。
2.2.RegistryProtocol
RegistryProtocol类核心功能:
- 主要是创建LocalExport。
- 将服务提供端服务其本身注册在本地。
public class RegistryProtocol implements Protocol, ScopeModelAware {
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
// service-discovery-registry://192.168.50.89:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-provider&dubbo=2.0.2&pid=57555&qos.enable=false®ister-mode=instance®istry=zookeeper&release=3.0.7×tamp=1708673397005
URL registryUrl = getRegistryUrl(originInvoker);
//dubbo://192.168.80.36:20880/image/common.service.CountryService?anyhost=true&application=dubbo-provider&background=false&bind.ip=192.168.80.36&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=common.service.CountryService&methods=getCountry&pid=57555&qos.enable=false®ister-mode=instance&release=3.0.7&revision=1.0&scope=remote&service-name-mapping=true&side=provider×tamp=1708674621496&version=1.0
URL providerUrl = getProviderUrl(originInvoker);
//provider://192.168.80.36:20880/image/common.service.CountryService?anyhost=true&application=dubbo-provider&background=false&bind.ip=192.168.80.36&bind.port=20880&category=configurators&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=common.service.CountryService&methods=getCountry&pid=57555&qos.enable=false®ister-mode=instance&release=3.0.7&revision=1.0&scope=remote&service-name-mapping=true&side=provider×tamp=1708674621496&version=1.0
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
...
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//export invoker
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// url to registry
final Registry registry = getRegistry(registryUrl);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true);
if (register) {
// 此处注册只是 在本地缓存注册信息
register(registry, registeredProviderUrl);
}
registerStatedUrl(registryUrl, registeredProviderUrl, register);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
...
return new DestroyableExporter<>(exporter);
}
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
String key = getCacheKey(originInvoker);
return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
// 最终返回的是 DubboProtocol 生成的 DubboExporter
return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
});
}
}
创建本地Exporter时涉及originInvoker是指最原始的Invoker之DelegateProviderMetaDataInvoker,通过该Invoker利用反射可以直接调用目标类的目标方法。
2.2.1.DubboProtocol
ExchangeHandler其实就是Netty涉及的channelHandler,服务提供端接收到消费端相关请求后通过该Handler得到原始的Invoker,触发目标类的目标方法。
public class DubboProtocol extends AbstractProtocol {
protected final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<>();
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
@Override
public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {
Invocation inv = (Invocation) message;
// 从集合属性 exporterMap 获取 原始的 invoker
Invoker<?> invoker = getInvoker(channel, inv);
inv.setServiceModel(invoker.getUrl().getServiceModel());
// need to consider backward-compatibility if it's a callback
if (Boolean.TRUE.toString().equals(inv.getObjectAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) {
String methodsStr = invoker.getUrl().getParameters().get("methods");
boolean hasMethod = false;
if (methodsStr == null || !methodsStr.contains(",")) {
hasMethod = inv.getMethodName().equals(methodsStr);
} else {
String[] methods = methodsStr.split(",");
for (String method : methods) {
if (inv.getMethodName().equals(method)) {
hasMethod = true;
break;
}
}
}
}
RpcContext.getServiceContext().setRemoteAddress(channel.getRemoteAddress());
// 利用原始的 invoker 调用目标类的目标方法
Result result = invoker.invoke(inv);
return result.thenApply(Function.identity());
}
};
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service.
String key = serviceKey(url);
// 将原始invoker 添加到 集合属性 exporterMap
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
...
// 此处触发提供端 Netty Server 的初始化,监听20880端口
openServer(url);
optimizeSerialization(url);
return exporter;
}
}
利用当前Protocol启动NettyServer。
3.zk客户端
zk注册中心注册的客户端:CuratorZookeeperClient。
public class ServiceConfig<T> extends ServiceConfigBase<T> {
private void exportUrl(URL url, List<URL> registryURLs) {
String scope = url.getParameter(SCOPE_KEY);
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
exportLocal(url);//直接注册在本地
}
// export to remote if the config is not local (export to local only when config is local)
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
//核心:根据相关协议徐序列化
url = exportRemote(url, registryURLs);
if (!isGeneric(generic) && !getScopeModel().isInternal()) {
// 真正通过zk客户度注册provider服务
MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel());
}
}
}
this.urls.add(url);
}
}