dubbo系列之@Service註解解析原理(四)
前言
前面幾篇文章,講的是除錯環境搭建,配置解析讀取,本文講的是dubbo如何解析@service註解的,瞭解這些東西對於真正使用dubbo來說,沒有直接的東西,但是這個是我後面要寫的dubbo核心功能原始碼解析的前提,前後連貫,這樣才能瞭解的更加清晰一點。
解析入口
@service註解解析入口有兩個地方,二者是二選一的
第一種
DubboAutoConfiguration
這個自動配置類中
@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這個類。
@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容器
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的方法是
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
這個類。
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,這個類裡面包含了服務釋出,服務下線等操作,算是一個很核心的類,後面會講到。