Dubbo中@Service工作過程解析


Dubbo中@Service工作過程解析

Spring中的BeanPostProcessor

首先我們應當了解到在spring體系中BeanPostProcessor是什么、加載流程

它是什么

BeanPostProcessor也也稱為后置處理器。在spring容加載流程。

spring容器bean加載流程
// Prepare this context for refreshing.
prepareRefresh();

// 獲取beanFactory並加載容器中定義的bean信息
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
	// 歸類bean工廠的后置處理器
	postProcessBeanFactory(beanFactory);

	// 處理這些bean工廠的后置處理器
	invokeBeanFactoryPostProcessors(beanFactory);

	// 調用所有實現了beanpostprocessor接口的類。(先加載實現了priority接口的,然后加載order的,最后加載剩余的)
	registerBeanPostProcessors(beanFactory);

	// Initialize message source for this context.
	initMessageSource();

	// Initialize event multicaster for this context.
	initApplicationEventMulticaster();

	// Initialize other special beans in specific context subclasses.
	onRefresh();

	// Check for listener beans and register them.
	registerListeners();

	// Instantiate all remaining (non-lazy-init) singletons.
	finishBeanFactoryInitialization(beanFactory);

	// Last step: publish corresponding event.
	finishRefresh();
}

后置處理器的加載和工作

所以由上可以看出,在registerBeanPostProcessors這一步的時候會划分容器中各種后置處理器,首先歸類有@Priority注解,其次歸類有@Order注解。最后划分其它的。

// 1
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// 2
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// 3
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

這樣,就將所有的后置處理器注冊到容器中。后續在容器啟動的過程中,會通過反射的方式調用各個實現了BeanPostProcessor的實現類的beforexxxxafterxxx的方法來做進一步的處理。

有了以上基礎,就可以去dubbo包中找到各自的xxxBeanPostProcessor了。
dubbo中提供的各個beanpostprocessor

dubbo中的ServiceAnnotationBeanPostProcessor

類繼承關系

類圖

作用

BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor,是一種比較特殊的BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor中定義的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法 可以讓我們實現自定義的注冊bean定義的邏輯。

從以上論述可以看出實現BeanDefinitionRegistryPostProcessor的作用就是向spring容器中注冊響應的bean實例。

具體分析

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    // 讀取配置中聲明的dubbo掃描類
    Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        // 將加有@Service注解的類注冊到spring容器中
        registerServiceBeans(resolvedPackagesToScan, registry);
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
    }

}

下面就分析registerServiceBeans的處理過程。

  1. 掃描系統配置的 basePackages,將@Service注解的類放到一個set集合中。
  2. 找到所有標注@Service的類是否被掃面到。
  3. registerServiceBean循環遍歷這個集合,並將它們注入到spring容器中。

ServiceBean的作用

類圖繼承關系

ServiceBean的類圖繼承關系
主要看它實現了InitializingBean。通過實現它來對bean初始化之后做一定操作(調用afterPropertiesSet())。

代碼實現

  1. ServiceBean初始化過程。如下所示:
@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
    // 進行大量的操作,來讀取對應的@Service組成相應的對象信息.....
    .....
    // 最后一步,導出服務。
    export()
}
  1. export()導出服務

    最后得到一系列的URL信息(形如注冊在zk上的provider節點信息)
export() -> doExportUrlsFor1Protocol()
  1. 獲取暴露的host和端口
// 獲取部署主機信息
 String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
// 獲取配置的端口信息。(默認20880,)
Integer port = this.findConfigedPorts(protocolConfig, name, map);
  1. 導出有兩步

    1. exportLocal
    2. exportJVM
  2. 根據第3步啟動相關的服務

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        // 
        URL url = invoker.getUrl();
    
        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        exporterMap.put(key, exporter);
    
        //export an stub service for dispatching event
        Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
        Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
        if (isStubSupportEvent && !isCallbackservice) {
            String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
            if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
                if (logger.isWarnEnabled()) {
                    logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
                            "], has set stubproxy support event ,but no stub methods founded."));
                }
    
            } else {
                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
            }
        }
        // 根據url配置host、port信息啟動服務(默認使用netty)
        openServer(url);
        optimizeSerialization(url);
    
        return exporter;
    }
    

    netty服務啟動

     private ExchangeServer createServer(URL url) {
        url = URLBuilder.from(url)
                // send readonly event when server closes, it's enabled by default
                .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
                // enable heartbeat by default
                .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
                .addParameter(CODEC_KEY, DubboCodec.NAME)
                .build();
        String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
    
        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
            throw new RpcException("Unsupported server type: " + str + ", url: " + url);
        }
    
        ExchangeServer server;
        try {
            server = Exchangers.bind(url, requestHandler);
        } catch (RemotingException e) {
            throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
        }
    
        str = url.getParameter(CLIENT_KEY);
        if (str != null && str.length() > 0) {
            Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
            if (!supportedTypes.contains(str)) {
                throw new RpcException("Unsupported client type: " + str);
            }
        }
    
        return server;
    }
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM