1. 整体架构
注: 本文基于Dubbo2.7.5版本,在这个版本里,服务暴露不是ServiceBean的功能了。
1.1 启动类与配置
package com.zyz;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
public class Application {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
}
}
2. 源码解析
2.1 EnableDubbo注解
先从该注解开始,这个注解的作用是对指定包下的类 进⾏扫描,扫描@Service与@Reference注解,并且进⾏处理。
查看该注解,发现包含两个很重要的注解@EnableDubboConfig和 @DubboComponentScan,根据名字猜测,一个是将配置文件中的属性转成Bean并赋值,一个是扫描@Service和@Reference的注解。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
@EnableDubboLifecycle
2.1.1 @EnableDubboConfig注解
进入该注解,发现@Import了DubboConfigConfigurationRegistrar类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
2.1.2 DubboConfigConfigurationRegistrar类
根据Spring的一惯作风,被@Import注解的类,会执行注册方法,把自己注册为一个Bean。那么来看下这个类的注册方法。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
//单一绑定配置
registerBeans(registry, DubboConfigConfiguration.Single.class);
//多个实例绑定配置
if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
//注册DubboConfigAliasPostProcessor后置处理器
registerDubboConfigAliasPostProcessor(registry);
//注册NamePropertyDefaultValueDubboConfigBeanCustomizer
registerDubboConfigBeanCustomizers(registry);
}
单一绑定和多实例绑定的意思就是这样:
单一绑定:
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
多实例绑定:
dubbo.protocols.p1.id=dubbo1
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20881
dubbo.protocols.p1.host=0.0.0.0
dubbo.protocols.p2.id=dubbo2
dubbo.protocols.p2.name=dubbo
dubbo.protocols.p2.port=20882
dubbo.protocols.p2.host=0.0.0.0
dubbo.protocols.p3.id=dubbo3
dubbo.protocols.p3.name=dubbo
dubbo.protocols.p3.port=20883
dubbo.protocols.p3.host=0.0.0.0
2.1.3 DubboConfigConfiguration类
该类的作用就是将配置文件中的配置信息与具体的类进行绑定。
比如:将dubbo.protocol同ProtocolConfig.class进行绑定。
public class DubboConfigConfiguration {
/**
* Single Dubbo {@link AbstractConfig Config} Bean Binding
*/
@EnableConfigurationBeanBindings({
@EnableConfigurationBeanBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.module", type = ModuleConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.metrics", type = MetricsConfig.class),
@EnableConfigurationBeanBinding(prefix = "dubbo.ssl", type = SslConfig.class)
})
public static class Single {
}
/**
* Multiple Dubbo {@link AbstractConfig Config} Bean Binding
*/
@EnableConfigurationBeanBindings({
@EnableConfigurationBeanBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
@EnableConfigurationBeanBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
})
public static class Multiple {
}
}
2.1.4 @EnableConfigurationBeanBindings
该注解就是包含所有配置信息,注意,该注解@Import了ConfigurationBeanBindingsRegister类。
2.1.5 ConfigurationBeanBindingsRegister类
既然是被注解@Import引入的,还是看这个类的注册方法。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//获取配置文件中的属性(用key-value存储的)
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableConfigurationBeanBindings.class.getName()));
//获取配置的属性,就是dubbo.registrie这些值
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
ConfigurationBeanBindingRegistrar registrar = new ConfigurationBeanBindingRegistrar();
registrar.setEnvironment(environment);
//循环注册bean
for (AnnotationAttributes element : annotationAttributes) {
registrar.registerConfigurationBeanDefinitions(element, registry);
}
}
2.1.6 registerConfigurationBeanDefinitions()方法
该方法将配置文件中的属性注册成一个bean
protected void registerConfigurationBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
Class<?> configClass = attributes.getClass("type");
boolean multiple = attributes.getBoolean("multiple");
boolean ignoreUnknownFields = attributes.getBoolean("ignoreUnknownFields");
boolean ignoreInvalidFields = attributes.getBoolean("ignoreInvalidFields");
registerConfigurationBeans(prefix, configClass, multiple, ignoreUnknownFields, ignoreInvalidFields, registry);
}
2.1.7 registerConfigurationBeans()方法
该方法将配置属性中的值注册为一个一个bean,但是这时候还没有赋值,而是通过注册一个赋值的后置处理器,后续进行赋值。
private void registerConfigurationBeans(String prefix, Class<?> configClass, boolean multiple,
boolean ignoreUnknownFields, boolean ignoreInvalidFields,
BeanDefinitionRegistry registry) {
Map<String, Object> configurationProperties = PropertySourcesUtils.getSubProperties(environment.getPropertySources(), environment, prefix);
if (CollectionUtils.isEmpty(configurationProperties)) {
if (log.isDebugEnabled()) {
log.debug("There is no property for binding to configuration class [" + configClass.getName()
+ "] within prefix [" + prefix + "]");
}
return;
}
//获取bean名称
Set<String> beanNames = multiple ? resolveMultipleBeanNames(configurationProperties) :
singleton(resolveSingleBeanName(configurationProperties, configClass, registry));
//注册为一个bean,但是不赋值。
for (String beanName : beanNames) {
registerConfigurationBean(beanName, configClass, multiple, ignoreUnknownFields, ignoreInvalidFields,
configurationProperties, registry);
}
//注册绑定bean属性值的后置处理器
registerConfigurationBindingBeanPostProcessor(registry);
}
2.1.8 ConfigurationBeanBindingPostProcessor类
这里就会用到Spring后置处理器的知识,首先通过postProcessBeanFactory对类进行初始化,然后当Spring容器调用第一个后置处理器的时候,将之前初始化的bean进行赋值。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//初始化bean工厂
this.beanFactory = beanFactory;
//初始化ConfigurationBeanBinder绑定器
initConfigurationBeanBinder();
initBindConfigurationBeanCustomizers();
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
BeanDefinition beanDefinition = getNullableBeanDefinition(beanName);
//判断是不是配置类型的Bean
if (isConfigurationBean(bean, beanDefinition)) {
//为Bean赋值
bindConfigurationBean(bean, beanDefinition);
//绑定后的处理,执行setName和getName方法
customize(beanName, bean);
}
return bean;
}
至此Dubbo就把我们在配置文件中配置的属性,转换为Dubbo的配置Bean,并赋值了。
总结一下整体流程。
2.2 获取@Service流程
查看@DubboComponentScan注解,发现@Import了DubboComponentScanRegistrar类,那么该类就是解析@Service与@Reference的类。
来看该类的注册方法。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//获取扫描包目录,也就是配置了dubbo.scan.base-packages或@EnableDubbo(scanBasePackages = "com.zyz.provider.service")的包
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//注册ServiceAnnotationBeanPostProcessor后置处理器,作用就是⼀旦扫描到某个@Service注解就把它以及被它注解的类当做⼀个Dubbo服务,进⾏服务导出
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
//2.3的时候分析
registerReferenceAnnotationBeanPostProcessor(registry);
}
2.2.1 registerServiceAnnotationBeanPostProcessor()方法
该方法主要是注册了ServiceAnnotationBeanPostProcessor类
2.2.2 ServiceAnnotationBeanPostProcessor类
这个类就是注册了被@Service注解的类。
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册DubboBootstrapApplicationListener类
registerBeans(registry, DubboBootstrapApplicationListener.class);
//再次解析扫描类
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
//注册ServiceBean
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
2.2.3 registerServiceBeans()方法
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
//初始化Dubbo自己的扫描类,扫描@Service注解
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
//初始化BeanName生成器
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
/**
* Add the compatibility for legacy Dubbo's @Service
*
* The issue : https://github.com/apache/dubbo/issues/4330
* @since 2.7.3
*/
scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));
for (String packageToScan : packagesToScan) {
//先注册被@Service注解的类,这里注册的是Spring的Bean
scanner.scan(packageToScan);
//找到Spring里的Bean(上边注册的)
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
//这里注册的是Dubbo的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 + "]");
}
}
}
}
2.2.4 registerServiceBean()方法
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
//获取被@Service注解的Class
Class<?> beanClass = resolveClass(beanDefinitionHolder);
//获取@Service注解
Annotation service = findServiceAnnotation(beanClass);
//获取@Service注解的属性值
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
//获取该类实现的接口
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
//获取该类名称
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
//获取ServiceBeanName,比如:ServiceBean:com.zyz.DemoService:async
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) {
//注册ServiceBean
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
if (logger.isInfoEnabled()) {
logger.info("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?");
}
}
}
至此分析完毕,这部分代码比较简单,就是注册了两个Bean。
2.3 获取@Reference流程
在2.2一节中有一个registerReferenceAnnotationBeanPostProcessor()方法, 该方法就是注册ReferenceAnnotationBeanPostProcessor这个后置处理器的,用来获取@Reference注解的类和方法,并注入属性。该类又继承了AbstractAnnotationBeanPostProcessor类。
2.3.1 AbstractAnnotationBeanPostProcessor
会先调用该类的postProcessPropertyValues()方法
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//获得所有注入属性
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;
}
2.3.2 findInjectionMetadata()方法
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
//获得缓存key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
//构建属性
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
"] for annotation metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
2.3.3 buildAnnotatedMetadata()方法
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
//获取类上的@Reference
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
//获取方法上的@Reference
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
return new AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
2.3.4 inject()方法
返回postProcessPropertyValues方法,看这一行
metadata.inject(bean, beanName, pvs);
看上面知道,返回的是这个对象AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata,这里会调用AnnotatedInjectionMetadata.inject方法进行遍历,由于该类里有这两个属性
private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements;
private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements;
所以会分别遍历,即调用AnnotatedFieldElement.inject方法。
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
//获得属性值
Class<?> injectedType = field.getType();
//获得注入对象
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
}
2.3.5 getInjectedObject()方法
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
//先从缓存拿
Object injectedObject = injectedObjectsCache.get(cacheKey);
//缓存没有,就初始化
if (injectedObject == null) {
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
return injectedObject;
}
2.3.6 doGetInjectedBean()方法
这里的referencedBeanName和referenceBeanName不太好理解,希望后续可以优化。
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
//生成ServiceBean:com.zyz.DemoService:default
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
//@Reference(version=default) com.zyz.DemoService
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
//创建ReferenceBean
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
//注册ReferenceBean
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
//缓存
cacheInjectedReferenceBean(referenceBean, injectedElement);
//创建代理
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
}
2.3.7 getOrCreateProxy()方法
private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<?> serviceInterfaceType) {
if (existsServiceBean(referencedBeanName)) { //本地服务存在的话,就创建代理
return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
wrapInvocationHandler(referenceBeanName, referenceBean));
} else {
// 应该去注册中心去拿服务,然后把对象创建出来
return referenceBean.get();
}
}
2.3.8 referenceBean.get()
对于这个方法,后续还要优化,如果可以确保获取远程服务的逻辑,在DubboLifecycleComponentApplicationListener事件之后,就可以避免启动DubboBootstrap.init(),因为DubboBootstrap是在DubboLifecycleComponentApplicationListener之后启动的。
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
if (ref == null) {
//初始化远程服务
init();
}
return ref;
}
至此源码分析完毕。