上一篇已经详细分析了dubbo的配置解析,本小节我们聊聊@Service注解。
当你使用@Service注解时有没有疑惑,这不是spring自带的注解,dubbo是如何扫描到该注解的,扫描到后又做了什么处理。
@EnableDubbo
@EnableDubbo(scanBasePackages = “org.apache.dubbo.demo.provider”)
@DubboComponentScan
public @interface EnableDubbo {
}
@DubboComponentScan
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] basePackages() default {};
}
DubboComponentScanRegistrar
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
//importingClassMetadata含有@DubboComponentScan的所有信息
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//拿到所有的包路径,即org.apache.dubbo.demo.provider
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//注册ServiceAnnotationBeanPostProcessor
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
//ReferenceAnnotationBeanPostProcessor,配置,监听器,懒加载
// 上篇博客说过这个,里面只剩下ReferenceAnnotationBeanPostProcessor没说
registerCommonBeans(registry);
}
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
//ServiceAnnotationBeanPostProcessor添加到spring容器,路径传给构造器
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
//把路径org.apache.dubbo.demo.provider当作构造器参数传给ServiceAnnotationBeanPostProcessor
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
//bd就注册好了
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
}
ServiceAnnotationBeanPostProcessor啥也没干,具体事情是它的父类ServiceClassPostProcessor做的,它实现了四个接口。
BeanDefinitionRegistryPostProcessor接口的方法是postProcessBeanDefinitionRegistry,是用来注册bd的,另外三个接口用来获取Environment,ResourceLoader, ClassLoader
public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
ResourceLoaderAware, BeanClassLoaderAware
我们来看看关键方法postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//这个上篇本博客也说到了,接收到onContextRefreshedEvent,调用dubboBootStrap.start(这里做了很多事,服务导出,服务引入)
//接收到onContextClosedEvent,调用dubboBootStrap.stop
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
//provider的包扫描路径
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
}
}
registerServiceBeans
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
//扫描器,其实就是spring的 ClassBeanDefinitionScanner
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
//beanname生成器
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
//扫描器要扫描哪些注解,这样scanner只会扫描出路径下带有这三个注解的服务实现类
//serviceAnnotationTypes有三个注解@Service,@Service(alibaba),@DubboService
serviceAnnotationTypes.forEach(annotationType -> {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
});
for (String packageToScan : packagesToScan) {
//注册添加了@Service 的bd
// 扫描出所有含有这三个注解的服务实现类,并注册了bd到spring容器
scanner.scan(packageToScan);
// 拿到上面这行代码添加的所有bd,BeanDefinitionHolder你可以理解为bd,二者一样
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
//为每一个上面的bd生成一个ServiceBean(ref放上面的bd) 的bd
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
//这里就是在注册ServiceBean了,ServiceBean的ref属性放真正的服务实现类的那个bd
registerServiceBean(beanDefinitionHolder, registry, scanner);
}
}
}
}
registerServiceBean(beanDefinitionHolder, registry, scanner);
注册ServiceBean之前我先解释dubbo为何要为每一个服务实现类bd生成一个ServiceBean,再用ref引用真正bd?
我们看一下原生api就明白了,因为原生写法是这样,整合spring的时候必须得这样,而且这样也方便统一管理,所有的服务提供者都是ServiceBean, 所有的服务消费者都是ReferenceBean
private static void startWithExport() throws InterruptedException {
//ServiceConfig即ServiceBean
ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());//ref引用真正的服务实现类
service.setApplication(new ApplicationConfig("dubbo-demo-api-provider"));
service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
service.export();//服务导出
System.out.println("dubbo service started");
new CountDownLatch(1).await();
}
//某个服务实现类bd,bd注册器,扫描器
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
//服务实现类DemoServiceImpl.class
Class<?> beanClass = resolveClass(beanDefinitionHolder);
//@Service注解,例如version,group,loadBalance等配置
Annotation service = findServiceAnnotation(beanClass);
//注解上所有配置信息
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
//服务实现类的接口类DemoService.class
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
//demoServiceImpl
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
//构建ServiceBean的bd,关键代码
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// 生成ServiceBean的 beaName,规则是ServiceBean:+接口全路径
//ServiceBean:org.apache.dubbo.demo.DemoService
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
//注册bd
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) {
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
}
}
buildServiceBeanDefinition
//@Service, @Service注解的配置,DemoService.class,真正bd的名字demoServiceImpl
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
AnnotationAttributes serviceAnnotationAttributes,
Class<?> interfaceClass,
String annotatedServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName", "parameters");
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
// ref引用真正的bd
addPropertyReference(builder, "ref", annotatedServiceBeanName);
//设置接口名字
builder.addPropertyValue("interface", interfaceClass.getName());
//从这往下都是从注解配置拿到信息添加到bd里面
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
// Add methods parameters
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
builder.addPropertyValue("methods", methodConfigs);
}
/**
* Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
*/
String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
if (StringUtils.hasText(providerConfigBeanName)) {
addPropertyReference(builder, "provider", providerConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
*/
String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
if (StringUtils.hasText(monitorConfigBeanName)) {
addPropertyReference(builder, "monitor", monitorConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
*/
String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
if (StringUtils.hasText(applicationConfigBeanName)) {
addPropertyReference(builder, "application", applicationConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
*/
String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
if (StringUtils.hasText(moduleConfigBeanName)) {
addPropertyReference(builder, "module", moduleConfigBeanName);
}
/**
* Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
*/
String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
if (!registryRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("registries", registryRuntimeBeanReferences);
}
/**
* Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
*/
String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
if (!protocolRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
}
return builder.getBeanDefinition();
}
总结
大体流程就是利用spring的scanner的includeFilter,过滤包含三个注解的服务实现类,把所有的服务实现类都注册bd,再为每一个bd生成一个ServiceBean, ref引用真正的服务实现类bd,注解的配置信息都放到ServiceBean bd的propertyValues里