歡迎關注公衆號【sharedCode】致力於主流中間件的源碼分析, 能夠直接與我聯繫java
前言
前面幾篇文章,講的是調試環境搭建,配置解析讀取,本文講的是dubbo如何解析@service註解的,瞭解這些東西對於真正使用dubbo來講,沒有直接的東西,可是這個是我後面要寫的dubbo核心功能源碼解析的前提,先後連貫,這樣才能瞭解的更加清晰一點。spring
解析入口
@service註解解析入口有兩個地方,兩者是二選一的app
第一種
DubboAutoConfiguration
這個自動配置類中ide
@ConditionalOnMissingBean @Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME) public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() { return new ReferenceAnnotationBeanPostProcessor(); } @ConditionalOnProperty(name = BASE_PACKAGES_PROPERTY_NAME) @ConditionalOnClass(RelaxedPropertyResolver.class) @Bean public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(Environment environment) { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment); Set<String> packagesToScan = resolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet()); return new ServiceAnnotationBeanPostProcessor(packagesToScan); }
上面兩個配置的做用,在上文中已經講解過,此處再也不贅述源碼分析
第二種
@SpringBootApplication @DubboComponentScan("com.dubbo.consumer.service") public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class); } }
請求頭上使用了@DubboComponentScan
註解,該註解是導入一個DubboComponentScanRegistrar這個類。post
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(DubboComponentScanRegistrar.class) public @interface DubboComponentScan { String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
DubboComponentScanRegistrar是一個實現了ImportBeanDefinitionRegistrar
接口的類,主要看registerBeanDefinitions
方法,該方法會實例化一些BeanDefinition進入spring容器ui
Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 獲取掃描包路徑 Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); // 註冊@service解析的類 registerServiceAnnotationBeanPostProcessor(packagesToScan, registry); // 註冊解析@Reference註解的bean registerReferenceAnnotationBeanPostProcessor(registry); }
在咱們的調試例子中,使用的是在啓動類中添加註解進行@DubboComponentScan
啓動的,因此這裏就按照這個方式來,其實第一種和第二種的方式是差很少的,最終都是經過初始化ServiceAnnotationBeanPostProcessor
這個類來達到解析@Service 並生成bean的目的。 接着上面的代碼講,註冊解析@@service的方法是.net
registerServiceAnnotationBeanPostProcessor
, 下面看一下這個方法。調試
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) { // 構建ServiceAnnotationBeanPostProcessor的 BeanDefinitionBuilder BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class); builder.addConstructorArgValue(packagesToScan); // 掃描的包 builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); // 建立BeanDefinition並註冊到容器中。 BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); }
這個方法就是這麼簡單,有些朋友可能以爲,就這幾行代碼,就可以解析@Service註解了? 徹底沒有看到解析的邏輯代碼呢。其實主要的在於ServiceAnnotationBeanPostProcessor
這個類。code
ServiceAnnotationBeanPostProcessor
public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { // 代碼省略 }
首先咱們看一下這個類他實現的接口,實現了BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware這四個接口, 主要看BeanDefinitionRegistryPostProcessor這個接口,看一下下面的官方解釋
**官方解釋 **
容許在正常的BeanFactoryPostProcessor檢測開始以前註冊更多的自定義bean。特別是,BeanDefinitionRegistryPostProcessor 能夠註冊更多的bean定義,而後定義BeanFactoryPostProcessor實例。也就是說能夠藉此方法實現自定義的bean,經過重寫postProcessBeanDefinitionRegistry方法來自定義bean
經過看上面的解釋,咱們直接找到postProcessBeanDefinitionRegistry
方法
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 獲取掃描包,掃描包能夠是多個,因此這裏使用了Set集合 Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan); // 判斷須要掃描的包是否爲空 if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) { // 不爲空則調用方法進行解析 registerServiceBeans(resolvedPackagesToScan, registry); } else { if (logger.isWarnEnabled()) { logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!"); } } }
registerServiceBeans
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) { // 定義掃描對象,該類繼承了ClassPathBeanDefinitionScanner類 DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader); // beanName解析器 BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry); scanner.setBeanNameGenerator(beanNameGenerator); // 這行代碼很重要,添加了過濾器, 一個註解過濾器,用來過濾出來寫了@Service註解的對象 scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); // 掃描正式開始,遍歷包 for (String packageToScan : packagesToScan) { // Registers @Service Bean first scanner.scan(packageToScan); // 開始查找添加了@Service註解的類 Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); // 找到了則不爲空 if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { // 循環。 for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { // 註冊serviceBean registerServiceBean(beanDefinitionHolder, registry, scanner); } if (logger.isInfoEnabled()) { logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]"); } } else { if (logger.isWarnEnabled()) { logger.warn("No Spring Bean annotating Dubbo's @Service was found under package[" + packageToScan + "]"); } } } }
上面的代碼,主要做用就是經過掃描過濾器,掃描包中添加了@Service註解的類。最後獲得BeanDefinitionHolder對象,調用registerServiceBean來註冊ServiceBean
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) { // 服務接口類對象 Class<?> beanClass = resolveClass(beanDefinitionHolder); // 找到@service註解 Service service = findAnnotation(beanClass, Service.class); // 接口服務的實現類對象 Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service); // 獲得bean的名稱 String annotatedServiceBeanName = beanDefinitionHolder.getBeanName(); // 構建ServiceBean對象的BeanDefinition,經過Service註解對象,以及接口服務的實現類生成ServiceBean AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName); // 構建ServuceBean的名稱 String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName); // 校驗Bean是否重複 if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean // 調用BeanDefinitionRegistry註冊。 registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { logger.warn("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } } else { if (logger.isWarnEnabled()) { logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + "] was be found , Did @DubboComponentScan scan to same package in many times?"); } } }
buildServiceBeanDefinition這個方法用來構建ServiceBean對象,每一個暴露出的服務,最終都會構建成一個ServiceBean,
private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) { // 生成ServiceBean對象BeanDefinitionBuilder BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class); // 獲取beanDefinition AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); // 屬性集合 MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); // 忽略的屬性,指的是AnnotationPropertyValuesAdapter中,不把如下屬性放到PropertyValues中去 String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface"); // propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames)); // 設置ref屬性 addPropertyReference(builder, "ref", annotatedServiceBeanName); // 服務的接口 builder.addPropertyValue("interface", interfaceClass.getName()); /** * 獲取註解中的provider屬性 */ String providerConfigBeanName = service.provider(); if (StringUtils.hasText(providerConfigBeanName)) { addPropertyReference(builder, "provider", providerConfigBeanName); } /** * 獲取註解中的monitor屬性 */ String monitorConfigBeanName = service.monitor(); if (StringUtils.hasText(monitorConfigBeanName)) { addPropertyReference(builder, "monitor", monitorConfigBeanName); } /** * 獲取註解中的application屬性 */ String applicationConfigBeanName = service.application(); if (StringUtils.hasText(applicationConfigBeanName)) { addPropertyReference(builder, "application", applicationConfigBeanName); } /** * 獲取註解中的模塊屬性 */ String moduleConfigBeanName = service.module(); if (StringUtils.hasText(moduleConfigBeanName)) { addPropertyReference(builder, "module", moduleConfigBeanName); } /** * 獲取註解中的註冊中心屬性 */ String[] registryConfigBeanNames = service.registry(); List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames); if (!registryRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("registries", registryRuntimeBeanReferences); } /** * 獲取註解中的協議屬性 */ String[] protocolConfigBeanNames = service.protocol(); List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); if (!protocolRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } return builder.getBeanDefinition(); }
最終dubbo解析出了ServiceBean對象的beandefinition放入了spring的容器。ServiceBean對於每一個暴露的服務來講很重要,每一個暴露的服務都擁有一個ServiceBean,這個類裏面包含了服務發佈,服務下線等操做,算是一個很核心的類,後面會講到。
歡迎關注公衆號【sharedCode】致力於主流中間件的源碼分析, 能夠直接與我聯繫