Dubbo之ServiceBean
什么是ServiceBean
dubbo的服务,生成的spring的bean定义类型都是ServiceBean。也就是dubbo的注解@Service和配置文件里的dubbo:service/生成的bean定义类型都是ServiceBean。
举个例子:
接口
package com.mytest.dubbo;
public interface DemoService {
}
实现类
package com.mytest.dubbo;
import com.alibaba.dubbo.config.annotation.Service;
@Service
public class DemoServiceImpl implements DemoService {
}
main方法
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoDubboConfig.class);
context.start();
ServiceBean bean = (ServiceBean)context.getBean("ServiceBean:com.mytest.dubbo.DemoService");
System.out.println(bean);
}
context.getBean(“ServiceBean:com.mytest.dubbo.DemoService”)获取到的就是dubbo服务的bean。
Dubbo服务的bean定义在哪配置?
Dubbo服务的bean定义在哪配置,也就是ServiceBean在哪里设置的?
以下代码展示都是基于2.6.12的版本
首先在配置类上增加注解@EnableDubbo,开启dubbo,接着就可以看下@EnableDubbo是怎么工作的,最终把ServiceBean注册到spring中的。
@Configuration
@EnableDubbo(scanBasePackages = "com.mytest.dubbo" )
public class DemoDubboConfig {
}
@EnableDubbo上有@DubboComponentScan,再看@DubboComponentScan上导入了DubboComponentScanRegistrar.class,该类实现了ImportBeanDefinitionRegistrar接口,springIOC在执行过程中会调用ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法,用于注册bean定义。
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
}
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
}
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
}
接着来看下registerBeanDefinitions方法,该方法往springIOC注册了ServiceAnnotationBeanPostProcessor bean定义,该类实现了BeanDefinitionRegistryPostProcessor接口,在springIOC执行过程中又会执行postProcessBeanDefinitionRegistry方法。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
registerReferenceAnnotationBeanPostProcessor(registry);
}
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
ResourceLoaderAware, BeanClassLoaderAware {
}
postProcessBeanDefinitionRegistry方法,调用了registerServiceBeans(resolvedPackagesToScan, registry),该方法会扫描加了注解@Service 的类,然后根据buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName)方法把相关信息和ServiceBean封装到一个bean定义中。
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
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!");
}
}
}
buildServiceBeanDefinition方法
private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass,
String annotatedServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
// 省略
}
以上过程,我们看到dubbo服务使用ServiceBean作为Spring的bean定义,接下来我们再看看ServiceBean如何进行导出的?
Dubbo服务如何进行导出?
SpringIOC在完成所有Bean定义和单例的初始化之后,会调用finishRefresh()方法,该方法会执行所有实现了ContextRefreshedEvent事件的监听器。
ServiceBean也是一个监听器,实现了ApplicationListener接口,具体方法实现:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
export() 方法就是具体的导出逻辑。export()往下跟,会调用protocol.export(wrapperInvoker)方法。
会调用3次该方法。
第一次会执行injvm协议,也就是导出到本地进程,该方法在com.alibaba.dubbo.config.ServiceConfig#exportLocal
private void exportLocal(URL url) {
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(LOCALHOST)
.setPort(0);
StaticContext.getContext(Constants.SERVICE_IMPL_CLASS).put(url.getServiceKey(), getServiceClass(ref));
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
}
}
第二次会执行dubbo协议,该方法是在com.alibaba.dubbo.registry.integration.RegistryProtocol#doLocalExport,也就是在注册时候会先执行dubbo协议,再执行registry协议
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
synchronized (bounds) {
exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return exporter;
}
第三次会执行registry协议,执行该协议时会先dubbo协议,具体可以看下RegistryProtocol类。
在执行到具体的协议之前,都会以责任链的形式执行以下封装类
QosProtocolWrapper -> ProtocolFilterWrapper -> ProtocolListenerWrapper
具体这几个协议底层是怎么执行的,下次再分享。