启动入口
以Dubbo官方示例为例,当配置文件类中加入注解@EnableDubbo,即完成开启Dubbo
package org.apache.dubbo.demo.provider;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
public class Application {
/**
* In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
* launch the 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 {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
}
}
@EnableDubbo注解分析
package org.apache.dubbo.config.spring.context.annotation;
import org.apache.dubbo.config.AbstractConfig;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注册Dubbo组件为Spring Beans
* 相当于DubboComponentScan和EnableDubboConfig注解的组合
* 只能应用于Spring 4.2及以上
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
// 扫描的包名
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* 需要被扫描的包中的某个Class
* 即该class对应的包下的所有class都会被扫描
*
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
/**
* 是否绑定到多个Spring Bean
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default false;
}
该注解中引入了两个注解
- @EnableDubboConfig
- 该注解又引入了DubboConfigConfigurationSelector,该类实现了ImportSelector,因此在启动Spring的过程中会注册该类中selectImports方法返回的全类名的bean,而此处返回了DubboConfigConfiguration.Single或者DubboConfigConfiguration.Multiple
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
if (multiple) {
return of(DubboConfigConfiguration.Multiple.class.getName());
} else {
return of(DubboConfigConfiguration.Single.class.getName());
}
}
- Single和Multiple中都加了@EnableDubboConfigBindings的注解,该注解又会引入DubboConfigBindingRegistrar类,该类实现了ImportBeanDefinitionRegistrar类,而在Spring启动过程中会被注册成bean并执行registerBeanDefinitions方法,该方法的参数中传入了@EnableDubboConfigBindings注解的元数据,以及BeanDifinitionRegistry用于注册beanDefinition。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取到注解属性
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBinding.class.getName()));
// 注册BeanDefinition
registerBeanDefinitions(attributes, registry);
}
- 此处主要做了两件事,1. 注册@EnableDubboConfigBinding上的各种Config,2. 注册多个用于处理各种Config的DubboConfigBindingBeanPostProcessor
for (String beanName : beanNames) {
registerDubboConfigBean(beanName, configClass, registry);
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
- 注册Config比较简单,就不说了
- DubboConfigBindingBeanPostProcessor这个类继承了BeanPostProcessor,InitializingBean和ApplicationContextAware,因此在初始化该Bean的时候会先调用它的setApplicationContext方法和afterPropertiesSet方法,然后在其他Config的bean实例化的时候会进入到postProcessBeforeInitialization中
- 主要说下afterPropertiesSet,这个方法中主要是先创建一个DubboConfigBinder,如果用户用户注入过DubboConfigBinder的实例,那就使用之前注入的,没有的话就新建一个DefaultDubboConfigBinder
@Override
public void afterPropertiesSet() throws Exception {
if (dubboConfigBinder == null) {
try {
dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
} catch (BeansException ignored) {
if (log.isDebugEnabled()) {
log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");
}
// Use Default implementation
dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
}
}
dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
}
- postProcessBeforeInitialization方法主要是为了从当前环境中比如配置文件,也就是本文开头@PropertySource("classpath:/spring/dubbo-provider.properties")中的配置,当然不仅限于此文件,该方法结束后Config文件中就有了初始的某些值了
- @DubboComponentScan
@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方法注册Bean
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
registerReferenceAnnotationBeanPostProcessor(registry);
}
- 该方法注册了两种类型的Bean,第一,ServiceAnnotationBeanPostProcessor,第二. ReferenceAnnotationBeanPostProcessor,分别处理服务提供者,服务消费者的逻辑
- 首先分析一下ServiceAnnotationBeanPostProcessor这个Bean,这个Bean继承自BeanDefinitionRegistryPostProcessor这个Bean工厂后置处理器,Bean工厂后置处理一般都用来作为扫描包,注册Bean使用。而这个类中就是用来扫描之前定义的basePackages或者basePackageClasses或者value计算出来的包路径, 最终将标注了@org.apache.dubbo.config.annotation.Service的类注册成ServiceBean
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 定义扫描器
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 定义需要包含的过滤器
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
for (String packageToScan : packagesToScan) {
// Registers @Service Bean first
scanner.scan(packageToScan);
// 扫描出所有的标注了@org.apache.dubbo.config.annotation.Service的Bean
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
// 利用上面扫描出来的bean,再分别注册一个类型为ServiceBean的bean,其中有一个属性ref,指向真正的@Service的bean
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 + "]");
}
}
}
}
- 而这个ServiceBean就是服务暴露的关键Bean,它继承了InitializingBean和ApplicationListener
- 执行afterPropertiesSet方法,这个方法看起来很长,其实就是为ServiceBean设置各种Config属性,通过我们的配置,会注入的Config的bean,再用这个bean来设置ServiceBean的属性,表明该serviceBean的application,provider,registry,protocol等等
public void afterPropertiesSet() throws Exception {
System.out.println("SeviceBean。。。");
// 找出当前这个service所对应的Provider,并set
if (getProvider() == null) {
Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
if (providerConfigMap != null && providerConfigMap.size() > 0) {
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
if (CollectionUtils.isEmptyMap(protocolConfigMap)
&& providerConfigMap.size() > 1) { // backward compatibility
List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() != null && config.isDefault()) {
providerConfigs.add(config);
}
}
if (!providerConfigs.isEmpty()) {
setProviders(providerConfigs);
}
} else {
ProviderConfig providerConfig = null;
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (providerConfig != null) {
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
}
providerConfig = config;
}
}
if (providerConfig != null) {
setProvider(providerConfig);
}
}
}
}
// 找出当前这个service所对应的Application,并set
if (getApplication() == null
&& (getProvider() == null || getProvider().getApplication() == null)) {
Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
for (ApplicationConfig config : applicationConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
}
if (applicationConfig != null) {
setApplication(applicationConfig);
}
}
}
// ............... 中间还有各种设置,此处省略
if (!supportedApplicationListener) {
export();
}
}
- 执行onApplicationEvent方法,当bean都实例化完成后,触发Spring的ApplicationContextRefresh事件,这里执行服务导出,后面就进入Dubbo的服务导出流程。
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
System.out.println("SeviceBean Export。。。");
export();
}
}
- 回到ReferenceAnnotationBeanPostProcessor这个bean后置处理器,这个后置处理器继承了InstantiationAwareBeanPostProcessorAdapter,MergedBeanDefinitionPostProcessor
- 首先创建Spring的Bean的过程中,会执行多次Bean后置处理器,其中一次就是applyMergedBeanDefinitionPostProcessors,这个方法会允许修改BeanDefinition,而此处会通过findReferenceMetadata方法去查找标注有@Reference直接的方法或字段的bean,并根据bean的名字创建metadata缓存。该方法主要是找出需要注入的属性或方法,类似于Spring自己提供的@Resource
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findReferenceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
private InjectionMetadata findReferenceMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.isNotEmpty(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
ReferenceInjectionMetadata 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 = buildReferenceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for reference metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
- 然后Spring会走到属性注入的逻辑,如果Spring中有InstantiationAwareBeanPostProcessor类型的bean后置处理器,通常都是用来进行属性注入的,比如Spring的CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor,而dubbo这里的ReferenceAnnotationBeanPostProcessor也是同样的道理,根据之前找到的注入点进行属性注入
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex);
}
return pvs;
}
- 注入属性点找到之后就会开始注入,但具体注入什么呢?进入到inject方法之后就会发现这里需要根据注入的属性的类型创建一个referenceBean,而这个referenceBean是一个实现了FactoryBean的类,此处会利用ReferenceBeanBuilder建造一个
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> referenceClass = field.getType();
referenceBean = buildReferenceBean(reference, referenceClass);
ReflectionUtils.makeAccessible(field);
field.set(bean, referenceBean.getObject());
}
- 建造的代码如下,首先创建一个ReferenceBean,然后通过为其设置属性
public final B build() throws Exception {
checkDependencies();
// 生成一个ReferenceBean
B bean = doBuild();
// 为其绑定属性,设置provider,application,registry等等,然后执行初始化后的方法
configureBean(bean);
if (logger.isInfoEnabled()) {
logger.info(bean + " has been built.");
}
return bean;
}
- 属性设置完成后调用上面代码中的getObject,获取一个真正需要注入的属性类型的对象,其实就是个动态代理对象。最终会执行到如下代码,对referenceBean进行初始化,这里就进入了dubbo自己的消费端的初始化过程。
public synchronized T get() {
checkAndUpdateSubConfigs();
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
基本到这里,dubbo与Spring的整合就完成了,后面再讲dubbo的服务导出与服务引用的具体过程。