Dubbo Spring启动流程

启动入口

以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;

}

该注解中引入了两个注解

  1. @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文件中就有了初始的某些值了
  1. @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的服务导出与服务引用的具体过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值