ピジョン登録と発見サービス

前:何であったか、ピジョンの最初のコールサーバ
ピジョンの前には、プロシージャ呼び出し要求を説明し、その後、ピジョンサービスは、それが呼び出し元によって知覚される方法で、私たちは、RPCは、通常、測定サービスを節約するために、レジストリを持っていることを知っていました情報(IP、ポート、など)ので、クライアントは、通話要求を完了するために、情報やサービスを得るために登録中心を通って行くことができるということ。どのようピジョンサービスの登録と発見メカニズムまで実装されていることになります。

登録サービス

まず、登録サービスの仕組みを見てください。
ピジョンにインターセプト処理クラスにサービス・インターフェースとサービスプロバイダ実装クラス、およびこれら2つの音符へ発信者をマークするために主に使用さ@Referenceと@Service注釈があるAnnotationBeanここではBeanPostProcessorのスプリングを介して達成され、クラス(その固体BeanDefinitionパッケージが実装するためのインタフェースBeanFactoryPostProcessorをスキャン@Serviceピジョンおよび関連クラス)プロセスを完了するためのインタフェース、ルックpostProcessAfterInitializationの方法:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// 先判断要注入相关属性的Bean是否在指定的注解扫描包下
		Class<?> beanClass = AopUtils.getTargetClass(bean);
		if (beanClass == null || !isMatchPackage(beanClass.getName())) {
			return bean;
		}

		// 判断类定义中是否存在@Service注解
		Service service = beanClass.getAnnotation(Service.class);
		if (service != null) {
			// 如果未自定义接口,则用当前beanClass
			Class serviceInterface = service.interfaceClass();
			if (void.class.equals(service.interfaceClass())) {
				serviceInterface = ServiceConfigUtils.getServiceInterface(beanClass);
			}
			if (serviceInterface == null) {
				serviceInterface = beanClass;
			}

			// 初始化ProviderConfig和ServerConfig,完成服务提供者配置和服务器配置的初始化
			ProviderConfig<Object> providerConfig = new ProviderConfig<Object>(serviceInterface, bean);
			providerConfig.setService(bean);
			providerConfig.setUrl(service.url());
			providerConfig.setVersion(service.version());
			providerConfig.setSharedPool(service.useSharedPool());
			providerConfig.setActives(service.actives());

			ServerConfig serverConfig = new ServerConfig();
			serverConfig.setPort(getDefaultPort(service.port()));
			serverConfig.setSuffix(service.group());
			serverConfig.setAutoSelectPort(service.autoSelectPort());
			providerConfig.setServerConfig(serverConfig);

			// 注册服务提供者,启动服务器,发布服务,完成pigeon提供方调用初始化
			ServiceFactory.addService(providerConfig);
		}

		// 解析bean中方法和属性是否包含Reference,完成bean作为服务调用方的依赖注入。
		postProcessBeforeInitialization(bean, beanName);
		return bean;
	}

ここに私たちの関係の登録プロセス、すなわちあるServiceFactory.addService()は、トリガーにその最終的な外観を実現するために、

public void doAddService(ProviderConfig providerConfig) {
        try {
            // 检查服务名
            checkServiceName(providerConfig);
            // 发布指定版本服务,同时解析服务方法
            ServicePublisher.addService(providerConfig);
            // 启动netty RPC服务器,作为服务提供方供调用方调用服务
            ServerConfig serverConfig = ProviderBootStrap.startup(providerConfig);
            // 更新serverConfig
            providerConfig.setServerConfig(serverConfig);
            // 实际发布服务,会将服务注册到注册中心,供调用方发现调用
            ServicePublisher.publishService(providerConfig, false);
        } catch (Throwable t) {
            throw new RpcException("error while adding service:" + providerConfig, t);
        }
    }

前記添加は、主に次の工程のために、サービスを解析:
対応するサービス解除キー= URLよりもあれば、一方大きく、設定されている場合、構成のバージョンかどうかを決定する、バージョンurlWithVersion、更新キー= urlWithVersionサービスで生成され、そして新しいを使用しますデフォルトのバージョンのバージョンを上書きするURL
サービスの実装が実現するインターフェース、初期化メソッド呼び出しInitializingService場合
ServiceMethodCache、すべてのストレージ・クラスを、すべてを通じてクラスを提供するサービスをServicePublisher作成:コールServiceMethodFactory.initを(URL)メソッドを呼び出しServiceMethodCacheのServiceMethodFactoryを初期化するために使用されますリレーショナル・アプローチをマッピングすることは要件とIDの方法は満たすために
最初のすべてのメソッドとオブジェクトクラス無視する
圧縮、ハッシュ方法のURL +「#」+メソッド名で行うかどうかを決定するための濾過方法。
コードは以下の通りです

public static <T> void addService(ProviderConfig<T> providerConfig) throws Exception {
    if (logger.isInfoEnabled()) {
        logger.info("add service:" + providerConfig);
    }
    String version = providerConfig.getVersion();
    String url = providerConfig.getUrl();
    // 默认版本,直接以url为key
    if (StringUtils.isBlank(version)) {
        serviceCache.put(url, providerConfig);
    } else {
        // urlWithVersion = url + "_" + version
        String urlWithVersion = getServiceUrlWithVersion(url, version);
        if (serviceCache.containsKey(url)) {
            // 如果已经存在,覆盖服务
            serviceCache.put(urlWithVersion, providerConfig);
            ProviderConfig<?> providerConfigDefault = serviceCache.get(url);
            String defaultVersion = providerConfigDefault.getVersion();
            // 如果默认服务存在默认版本,并且小于当前版本,用当前版本服务更新默认服务版本
            if (!StringUtils.isBlank(defaultVersion)) {
                if (VersionUtils.compareVersion(defaultVersion, providerConfig.getVersion()) < 0) {
                    serviceCache.put(url, providerConfig);
                }
            }
        } else {
            // 将当前版本设为指定版本服务和默认版本服务
            serviceCache.put(urlWithVersion, providerConfig);
            // use this service as the default provider
            serviceCache.put(url, providerConfig);
        }
    }
    // 如果服务实现了InitializingService接口,调用实现的initialize方法
    T service = providerConfig.getService();
    if (service instanceof InitializingService) {
        ((InitializingService) service).initialize();
    }
    // 解析接口自定义方法,根据方法名,参数等相关信息记录方法
    ServiceMethodFactory.init(url);
}

// ServiceMethodFactory.init(url);方法实现如下:
public static void init(String url) {
    getServiceMethodCache(url);
}
// 具体调用了
public static ServiceMethodCache getServiceMethodCache(String url) {
    // 是否存在指定url的ServiceMethodCache
    ServiceMethodCache serviceMethodCache = methods.get(url);
    if (serviceMethodCache == null) {
        // 获取指定url的providerConfig
        Map<String, ProviderConfig<?>> services = ServicePublisher.getAllServiceProviders();
        ProviderConfig<?> providerConfig = services.get(url);
        if (providerConfig != null) {
            Object service = providerConfig.getService();
            Method[] methodArray = service.getClass().getMethods();
            serviceMethodCache = new ServiceMethodCache(url, service);
            // 遍历指定url的所有服务方法
            for (Method method : methodArray) {
                // 忽略掉Object和Class的所有方法
                if (!ingoreMethods.contains(method.getName())) {
                    method.setAccessible(true);
                    serviceMethodCache.addMethod(method.getName(), new ServiceMethod(service, method));

                    if (isCompact) {
                        // 压缩url,方法名等调用所需信息
                        int id = LangUtils.hash(url + "#" + method.getName(), 0, Integer.MAX_VALUE);
                        ServiceId serviceId = new ServiceId(url, method.getName());
                        ServiceId lastId = CompactRequest.PROVIDER_ID_MAP.putIfAbsent(id, serviceId);
                        // 检查如果存在相同id服务方法,抛异常
                        if (lastId != null && !serviceId.equals(lastId)) {
                            throw new IllegalArgumentException("same id for service:" + url + ", method:"
                                    + method.getName());
                        }
                    }

                }
            }
            // 更新缓存
            methods.put(url, serviceMethodCache);
        }
    }
    return serviceMethodCache;
}

主に、リッスンするネッティーサーバ側のインタフェースを指しリクエスト処理スレッドプールと初期化を開始し、サービスを開始します(要求処理スレッドプールのコールチェーン)、として、次のとおりです。
ここに画像を挿入説明
ここでは、配布方法キーサービスを見てServicePublisher.publishServiceメインロジック
ここに画像を挿入説明
サービスのニーズ場合呼ばれるここにサインアップpublishServiceToRegistryの登録および通知サービスの変更を完了ZKで耐久性のあるノードを作成することによって、登録サービスへの道。

追加します

公開された19元の記事 ウォンの賞賛1 ビュー5324

おすすめ

転載: blog.csdn.net/qq_32231495/article/details/104041689