开头
dubbo一般会搭配spring集成使用,spring作为一个优秀的开源框架,提供了很多扩展点供第三方框架集成。
说到底,spring和dubbo集成,就是把dubbo中的诸多对象交由spring管理,比如配置类、protocol等。
在了解集成前,需要对上节dubbo的SPI机制有很清晰的了解,并且需要对spring的源码有一定的了解,比如spring的beanDefiniton、扩展点等,不然代码会看的一脸蒙蔽
精简流程
dubbo和spring集成主要做了下面三件事
1.解析配置文件,将配置文件解析成dubbo的bean,生成满足spring条件的beanDefinition
2.@DubboComponentScan包扫描,准备处理自定义包路径下的@Service和@Reference注解
3.处理dubbo服务端@Service注解
4.处理dubbo消费端@Reference注解
5.服务导出(属于Spring容器启动完成后的监听时间,后面单独章节写)
源码流程
地址:
https://www.processon.com/view/link/60e02b8d637689510d6c4184
解析配置文件
dubbo集成spring的总入口为@EnableDubbo,然后点进去@EnableDubboConfig,看到@Import导入了一个DubboConfigConfigurationRegistrar类,import注解表示加载配置文件的时候会加载该类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @revised 2.5.9
*/
boolean multiple() default true;
}
这里有一个重要的方法 , registerBeans(registry, DubboConfigConfiguration.Single.class);流程见下图,
DubboConfigConfiguration这个类很重要
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
})
EnableDubboConfigBinding这个注解在启动时候会加载DubboConfigBindingRegistrar,这个类实现了ImportBeanDefinitionRegistrar接口,该接口是spring提供的一个扩展点,实现这个接口会调用自定义的registerBeanDefinitions接口,可对beanDefinitions进行自定义 。
registerDubboConfigBeans开始对配置文件进行解析,如// dubbo.protocols.p1.port=20880
最终会将所以配置文件翻译成spring的beanDefinition对象
@DubboComponentScan包扫描
在@EnableDubbo注解中集合了@DubboComponentScan注解,@Import导入了启动配置类DubboComponentScanRegistrar。
流程为
@EnableDubbo->@DubboComponentScan->DubboComponentScanRegistrar->registerServiceAnnotationBeanPostProcessor(注册@Service注解)->registerReferenceAnnotationBeanPostProcessor((注册@Reference注解))
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("执行DubboComponentScanRegistrar");
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//处理service注解
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
//处理reference注解
registerReferenceAnnotationBeanPostProcessor(registry);
}
解析@Service注解
在服务者这一端,如果想把自己的接口提供给消费者远程调用,在接口实现类加入@Service注解接口,
@Service注解,和spring的@Service需区别,dubbo的@Service注解是将对应的bean导出成dubbo服务的。
回过头来,registerServiceAnnotationBeanPostProcessor一共会完成三件事
1.生成spring需要的普通beanDefiniton,如DemoServiceImpl
2.生成一个dubbo的ServiceBean,这个bean很重要,后面的服务导出需要依赖他
3.在serviceBean会注册监听spring容器启动事件,spring启动完成后,会调用serviceBean.onEvent事件进行服务导出
@Service源码解析
1.注册ServiceAnnotationBeanPostProcessor,由于该接口实现BeanDefinitionRegistryPostProcessor,所以spring启动调用ServiceAnnotationBeanPostProcessor.postProcessBeanDefinitionRegistry
2.registerServiceBeans扫描包,进行普通Bean注册,扫描被Service注解标注的类
3.注册ServiceBean,详见ServiceAnnotationBeanPostProcessor.buildServiceBeanDefinition
ServiceBean中有很多重要的属性,比如ref-服务实现类、protocol协议、interfaceName接口名字、applicationEventPublisher spring监听器
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
// @Service注解
Annotation service = findServiceAnnotation(beanClass);
// @Service注解上的信息
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
// 生成一个ServiceBean
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
}
4.serviceBean监听spring启动事件,进行服务导出,服务导出比较复杂,后面单独一节写
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
// 服务导出(服务注册)
export();
}
}
解析@Reference注解
在消费者这一端,如果想要远程调用服务者提供的接口,在调用的接口上加入@Reference即可。
回过头来,registerReferenceAnnotationBeanPostProcessor一共会完成三件事,和@Service有点类似
1.生成referenceBean对象
2.生成服务接口代理对象
@Reference源码解析
1.注册ReferenceAnnotationBeanPostProcessor,继承了spring的BeanPostProcessor
2.回调时机:spring依赖注入的时候,调用AnnotationInjectedBeanPostProcessor.postProcessPropertyValues
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
// 寻找需要注入的属性(被@Reference标注的Field)
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
3.寻找注入点,2步骤中findInjectionMetadata.buildAnnotatedMetadata
4.找到注入点后,使用new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata注入
5.注入的时候调用AnnotatedInjectionMetadata.inject
6.调用ReferenceAnnotationBeanPostProcessor.doGetInjectedBean
这里做了两件事:1.生成referencedBean代理对象 2.将referencedBean中的beanName注册到spring容器,如demoServiceImpl
7.生成referencedBean代理对象,这里单独拿出来,这里调用了一个很重要的方法getOrCreateProxy,这里会作为服务引入的入口,也就是消费端如何通过注册中心调用到服务端的,流程很复杂,后面单独再写
private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<?> serviceInterfaceType) {
if (existsServiceBean(referencedBeanName)) { // If the local @Service Bean exists, build a proxy of ReferenceBean
return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
wrapInvocationHandler(referenceBeanName, referenceBean));
} else { // ReferenceBean should be initialized and get immediately
// 很重要
return referenceBean.get();
}
}
ReferenceBean几个重要属性:
1.REF_PROTOCOL协议,可以看到采用的SPI机制
private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
- PROXY_FACTORY 代理工厂,后面会要生成很多服务的代理对象、dubbo的代理对象
private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
总结
看到这里,还只是完成了spring的整合,dubbo的核心源码还没有出现,比如服务是如何注册导出的、如何引入、如何调用的,后续会单独写