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
的實現類的beforexxxx
和afterxxx
的方法來做進一步的處理。
有了以上基礎,就可以去dubbo包中找到各自的
xxxBeanPostProcessor
了。
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
的處理過程。
- 掃描系統配置的
basePackages
,將@Service
注解的類放到一個set集合中。 - 找到所有標注
@Service
的類是否被掃面到。 registerServiceBean
循環遍歷這個集合,並將它們注入到spring容器中。
ServiceBean的作用
類圖繼承關系
主要看它實現了InitializingBean
。通過實現它來對bean初始化之后做一定操作(調用afterPropertiesSet()
)。
代碼實現
- ServiceBean初始化過程。如下所示:
@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
// 進行大量的操作,來讀取對應的@Service組成相應的對象信息.....
.....
// 最后一步,導出服務。
export()
}
- export()導出服務
最后得到一系列的URL信息(形如注冊在zk上的provider節點信息)
export() -> doExportUrlsFor1Protocol()
- 獲取暴露的host和端口
// 獲取部署主機信息
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
// 獲取配置的端口信息。(默認20880,)
Integer port = this.findConfigedPorts(protocolConfig, name, map);
-
導出有兩步
- exportLocal
- exportJVM
-
根據第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; }