SpringCloud Alibaba系列——5Dubbo整合spring(下)

老老老JR老北
发布于 2022-8-24 16:39
浏览
0收藏

作者 | 一起撸Java
来源 |今日头条

学习目标
本文主要讲解Dubbo基于注解的方式集成spring
第2章 注解方式整合
注解方式已经是现在的主流了,例如springboot现在都是零xml配置了,只要通过少量的配置就可以完成框架的引用。

2.1 案例
生产者

配置类

@Configuration//作用 扫描 @DubboService注解 @DubboReference@EnableDubbo(scanBasePackages = "com.example")@PropertySource("classpath:/dubbo-provider.properties")public class ProviderConfiguration {}

dubbo-provider.properties配置

dubbo.application.name=dubbo_providerdubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181dubbo.protocol.name=dubbodubbo.protocol.port=20880dubbo.config-center.address=zookeeper://${zookeeper.address:127.0.0.1}:2181

服务暴露

@DubboServicepublic class UserServiceImpl implements UserService {    @Override    public String queryUser(String s) {        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(s);        System.out.println("==========provider===========" + s);        return "OK--" + s;    }    @Override    public void doKill(String s) {        System.out.println("==========provider===========" + s);    }}

启动

public class AnnotationProvider {    public static void main(String[] args) throws InterruptedException {        ZKTools.generateDubboProperties();        new AnnotationConfigApplicationContext(ProviderConfiguration.class);        System.out.println("dubbo service started.");        new CountDownLatch(1).await();    }}

2.2 优势
可以看到,只需要在需要暴露的服务上面加上一个@DubboService注解就可以完成服务的暴露了,配置量非常少,但是这种方式也有一定的侵入性。

2.3 源码分析
2.3.1 @EnableDubbo
@EnableDubbo注解可以理解为引入dubbo功能,其实在这里它起到的作用就是两个,

1、扫描类上面的@DubboService注解

2、扫描类中属性或者方法上面的@DubboReference注解

那为什么@EnableDubbo会被spring扫描到呢?

要回答这个问题,首先我们得看看@EnableDubbo的结构。SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区可以看到,在@DubboComponentScan注解中有一个@Import注解,实际上spring能扫描到的就是这个@Import注解,通过扫描到@Import注解从而把import进来的
类变成BeanDefinition交给spring实例化。

具体spring如何扫描的,请看下面步骤:

1、通过spring上下文对象的实例化把
ConfigurationClassPostProcessor变成BeanDefinitionSpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区2、ConfigurationClassPostProcessor对@Import的扫描

由于ConfigurationClassPostProcessor类是一个BeanDefinitionRegistryPostProcessor类型的,所以在spring容器中它会优先被实例化,实例化的地方在refresh核心方法的:SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区所以当ConfigurationClassPostProcessor实例化的时候就调用到postProcessBeanDefinitionRegistry方法,方法逻辑如下:

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {    int registryId = System.identityHashCode(registry);    if (this.registriesPostProcessed.contains(registryId)) {        throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against" + registry);    }    if (this.factoriesPostProcessed.contains(registryId)) {        throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " +registry);    }    this.registriesPostProcessed.add(registryId);    //核心逻辑,重点看,重要程度5    processConfigBeanDefinitions(registry);}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();    //获取所有的beanNames    String[] candidateNames = registry.getBeanDefinitionNames();    for (String beanName : candidateNames) {        BeanDefinition beanDef = registry.getBeanDefinition(beanName);        //如果有该标识就不再处理        if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {            if (logger.isDebugEnabled()) {                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);            }        }        //判断是否是候选的需要处理的BeanDefinition,如果是则放入容器configCandidates        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));        }    }    // Return immediately if no @Configuration classes were found    //如果容器为空,则直接返回    if (configCandidates.isEmpty()) {        return;    }    // Sort by previously determined @Order value, if applicable    //对需要处理的所有beanDefinition排序    configCandidates.sort((bd1, bd2) -> {        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());        return Integer.compare(i1, i2);    });    // Detect any custom bean name generation strategy supplied through the enclosing application context    SingletonBeanRegistry sbr = null;    if (registry instanceof SingletonBeanRegistry) {        sbr = (SingletonBeanRegistry) registry;        if (!this.localBeanNameGeneratorSet) {            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);            if (generator != null) {                this.componentScanBeanNameGenerator = generator;                this.importBeanNameGenerator = generator;            }        }    }    if (this.environment == null) {        this.environment = new StandardEnvironment();    }    //候选BeanDefinition的解析器    // Parse each @Configuration class    ConfigurationClassParser parser = new ConfigurationClassParser(        this.metadataReaderFactory, this.problemReporter, this.environment,        this.resourceLoader, this.componentScanBeanNameGenerator, registry);    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());    do {        //解析核心流程,重点看,重要程度5        //其实就是把类上面的特殊注解解析出来最终封装成beanDefinition        parser.parse(candidates);        parser.validate();        Set<ConfigurationClass> configClasses = new LinkedHashSet<>            (parser.getConfigurationClasses());        configClasses.removeAll(alreadyParsed);        // Read the model and create bean definitions based on its content        if (this.reader == null) {            this.reader = new ConfigurationClassBeanDefinitionReader(                registry, this.sourceExtractor, this.resourceLoader, this.environment,                this.importBeanNameGenerator, parser.getImportRegistry());        }        //@Bean @Import 内部类 @ImportedResource ImportBeanDefinitionRegistrar具体处理逻辑        this.reader.loadBeanDefinitions(configClasses);        //已经解析完成了的类        alreadyParsed.addAll(configClasses);        candidates.clear();        //比较差异又走一遍解析流程        if (registry.getBeanDefinitionCount() > candidateNames.length) {            String[] newCandidateNames = registry.getBeanDefinitionNames();            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));            Set<String> alreadyParsedClasses = new HashSet<>();            for (ConfigurationClass configurationClass : alreadyParsed) {                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());            }            for (String candidateName : newCandidateNames) {                if (!oldCandidateNames.contains(candidateName)) {                    BeanDefinition bd = registry.getBeanDefinition(candidateName);                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd,                                                                                 this.metadataReaderFactory) &&                        !alreadyParsedClasses.contains(bd.getBeanClassName())) {                        candidates.add(new BeanDefinitionHolder(bd, candidateName));                    }                }            }            candidateNames = newCandidateNames;        }    }    while (!candidates.isEmpty());    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes        if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());        }    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {        // Clear cache in externally provided MetadataReaderFactory; this is a no-op        // for a shared cache since it'll be cleared by the ApplicationContext.        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();    }}

就是在上面方面里面的this.reader.loadBeanDefinitions(configClasses);这行代码对所有BeanDefinition中对应类上如果有@Import注解进行了解析处理,这样spring就能够扫描的@EnableDubbo注解了。

2.3.2 DubboComponentScanRegistrar

DubboComponentScanRegistrar类是通过@EnableDubbo上面的@DubboComponentScan注解import进来的,它是一个ImportBeanDefinitionRegistrar类型的,所有当被引入进来以后就会被spring调用到它的registerBeanDefinitions方法,代码如下:

@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {    // @since 2.7.6 Register the common beans    registerCommonBeans(registry);    Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);    registerServiceAnnotationPostProcessor(packagesToScan, registry);}

至于为什么spring能调到这个方法,起调用逻辑还是在this.reader.loadBeanDefinitions(configClasses);这行代码里面,具体调用代码:

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar,AnnotationMetadata> registrars) {    registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry,                                                                                  this.importBeanNameGenerator));}

我们在来看看registerBeanDefinitions方法做了些什么, registerCommonBeans(registry);方法前面我们分析过,注册了两个比较重要的类

1、ReferenceAnnotationBeanPostProcessor

2、DubboBootstrapApplicationListener

registerServiceAnnotationPostProcessor(packagesToScan, registry);这行代码里面又注册了一个比较重要的类,ServiceAnnotationPostProcessor

所以该方法其实核心就是注册了三个比较重要的类给了spring容器:

1、ReferenceAnnotationBeanPostProcessor

2、DubboBootstrapApplicationListener

3、ServiceAnnotationPostProcessor

DubboBootstrapApplicationListener这个类前面我们分析过,它就是在spring容器启动完成后通过spring发布一个spring容器启动完成的事件,然后该类捕获到事件,通过捕获事件来完成服务的发布和引用的,这里就不再赘述了。现在主要分析ServiceAnnotationPostProcessor和ReferenceAnnotationBeanPostProcessor

2.3.3 ServiceAnnotationPostProcessor
首先这个ServiceAnnotationPostProcessor类是干什么的呢?

这个类的作用就是用来扫描类上面的@DubboService注解的,就只有这个功能。

该类的类型是BeanDefinitionRegistryPostProcessor类型的。所以它会被spring调用到postProcessBeanDefinitionRegistry方法,调用逻辑如下:

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws    BeansException {    this.registry = registry;    Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {        //这里是扫描的核心逻辑        scanServiceBeans(resolvedPackagesToScan, registry);    } else {        if (logger.isWarnEnabled()) {            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");        }    }}
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {    //定义一个扫描器,这个dubbo扫描器其实就是继承了spring的ClassPathBeanDefinitionScanner扫描器    DubboClassPathBeanDefinitionScanner scanner =        new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);    scanner.setBeanNameGenerator(beanNameGenerator);    //对扫描器添加需要扫描的注解类型,这里的注解类型有三种,阿帕奇的@Service,@DubboService,阿里巴巴的@Service    for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {        scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));    }    ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();    scanner.addExcludeFilter(scanExcludeFilter);    for (String packageToScan : packagesToScan) {        // avoid duplicated scans        if (servicePackagesHolder.isPackageScanned(packageToScan)) {            if (logger.isInfoEnabled()) {                logger.info("Ignore package who has already bean scanned: " + packageToScan);            }            continue;        }        //这里就是核心的扫描代码        //扫描的核心流程,其实就是递归找文件的过程,如果找的是文件夹则递归找,如果是文件则根据完整限定名反射出反射对象,根据反射对象判断类上是否有DubboService注解,如果又则把该类变成BeanDefinition        // Registers @Service Bean first        scanner.scan(packageToScan);        // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.        Set<BeanDefinitionHolder> beanDefinitionHolders =            //这行代码就是根据前面的扫描找到的BeanDefinition集合,获取这个集合            findServiceBeanDefinitionHolders(scanner, packageToScan, registry,beanNameGenerator);        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {            if (logger.isInfoEnabled()) {                List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {                    serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());                }                logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);            }            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {                //这行代码很重要,因为要完成服务暴露那么就必须调用到ServiceBean中的export方法                //这行代码就是根据有注解的类的BeanDefinition来创建根该类对应的ServiceBean的BeanDefinition对象                processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);                servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());            }        } else {            if (logger.isWarnEnabled()) {                logger.warn("No class annotated by Dubbo @Service was found under package [" + packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());            }        }        servicePackagesHolder.addScannedPackage(packageToScan);    }}
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder,                                          BeanDefinitionRegistry registry,                                          DubboClassPathBeanDefinitionScanner scanner) {    Class<?> beanClass = resolveClass(beanDefinitionHolder);    Annotation service = findServiceAnnotation(beanClass);    // The attributes of @Service annotation    Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service,                                                                                    true);    String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);    String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();    // ServiceBean Bean name    String beanName = generateServiceBeanName(serviceAnnotationAttributes,                                              serviceInterface);    AbstractBeanDefinition serviceBeanDefinition =        //这里就是创建ServiceBean的BeanDefinition        buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface,                                   annotatedServiceBeanName);    registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);}

OK,从上面的分析,我们知道,扫描到有@DubboService注解的类以后,实际上会创建跟该类对应的ServiceBean的实例,也就是有一个@DubboService注解的类就会对应一个ServiceBean的实例在spring容器中。那么又回到了上面xml分析的流程了,ServiceBean实例化走到afterPropertiesSet方法,然后spring容器启动完成走到dubbo的监听器完成服务发布了。

2.3.4 ReferenceAnnotationBeanPostProcessor

ReferenceAnnotationBeanPostProcessor的作用就是完成@DubboReference属性或者方法的依赖注入,其依赖注入的流程也是完全依赖spring的,所以我们必须要掌握spring的依赖注入流程,其实spring的依赖注入核心就两点;

2.3.4.1 spring的依赖注入
1、注解的收集

2、实例的注入

以@Autowired注解的属性来分析spring的依赖注入,例如:

@Componentpublic class SpringTest {    @Autowired    private UserService userService;    private UserService userService1;    private UserService userService2;    private UserService userService3;    private UserService userService4;    public UserService getUserService() {        return userService;    }    @PostConstruct    public void init() {        System.out.println(userService);    }}

1、@Autowired注解收集

注解收集的核心流程

refresh--->finishBeanFactoryInitialization--->preInstantiateSingletons--->beanFactory.getBean--->AbstractBeanFactory.doGetBean--->createBean--->doCreateBean--->applyMergedBeanDefinitionPostProcessors

SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区对应的接口类型MergedBeanDefinitionPostProcessor,这个类型的BeanPostProcessor的埋点就是用来处理注解收集这个功能点的,只有关系该功能点的类才会对该接口的方法进行实现,其他不关心的可以不管MergedBeanDefinitionPostProcessor该接口的方法实现,也就是方法可以直接是一个空方法。SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区

AutowiredAnnotationBeanPostProceessor类就是用来对@Autowired注解进行支持的。该类的注册是在spring上下文对象的构造函数的完成注册的。

@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {    //注解收集核心逻辑    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);    metadata.checkConfigMembers(beanDefinition);}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {    // Fall back to class name as cache key, for backwards compatibility with custom callers.    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());    // Quick check on the concurrent map first, with minimal locking.    //先从缓存拿结果    InjectionMetadata 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);                }                //主要看这个方法                //收集的核心逻辑                metadata = buildAutowiringMetadata(clazz);                this.injectionMetadataCache.put(cacheKey, metadata);            }        }    }    return metadata;}
//其实这里就是拿到类上所有的field,然后判断field上是否有@Autowired注解,如果有则封装成对象//寻找field上面的@Autowired注解并封装成对象ReflectionUtils.doWithLocalFields(targetClass, field -> {    MergedAnnotation<?> ann = findAutowiredAnnotation(field);    if (ann != null) {        if (Modifier.isStatic(field.getModifiers())) {            if (logger.isInfoEnabled()) {                logger.info("Autowired annotation is not supported on static fields: " + field);            }            return;        }        boolean required = determineRequiredStatus(ann);        currElements.add(new AutowiredFieldElement(field, required));    }});

注解的收集就完成了

2、@Autowired的依赖注入

依赖注入的核心方法:

//ioc di,依赖注入的核心方法,该方法必须看,重要程度:5populateBean(beanName, mbd, instanceWrapper);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {    if (bw == null) {        if (mbd.hasPropertyValues()) {            throw new BeanCreationException(                mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");        }        else {            // Skip property population phase for null instance.            return;        }    }    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the    // state of the bean before properties are set. This can be used, for example,    // to support styles of field injection.    //这里很有意思,写接口可以让所有类都不能依赖注入    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {        for (BeanPostProcessor bp : getBeanPostProcessors()) {            if (bp instanceof InstantiationAwareBeanPostProcessor) {                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {                    return;                }            }        }    }    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);    int resolvedAutowireMode = mbd.getResolvedAutowireMode();    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE)    {        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);        // Add property values based on autowire by name if applicable.        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {            autowireByName(beanName, mbd, bw, newPvs);        }        // Add property values based on autowire by type if applicable.        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {            autowireByType(beanName, mbd, bw, newPvs);        }        pvs = newPvs;    }    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();    boolean needsDepCheck = (mbd.getDependencyCheck() !=                             AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);    PropertyDescriptor[] filteredPds = null;    //重点看这个if代码块,重要程度 5    if (hasInstAwareBpps) {        if (pvs == null) {            pvs = mbd.getPropertyValues();        }        for (BeanPostProcessor bp : getBeanPostProcessors()) {            if (bp instanceof InstantiationAwareBeanPostProcessor) {                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;                //依赖注入过程,@Autowired的支持。。这里完成了依赖注入                PropertyValues pvsToUse = ibp.postProcessProperties(pvs,bw.getWrappedInstance(), beanName);                if (pvsToUse == null) {                    if (filteredPds == null) {                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);                    }                    //老版本用这个完成依赖注入过程,@Autowired的支持                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds,bw.getWrappedInstance(), beanName);                    if (pvsToUse == null) {                        return;                    }                }                pvs = pvsToUse;            }        }    }    if (needsDepCheck) {        if (filteredPds == null) {            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);        }        checkDependencies(beanName, mbd, filteredPds, pvs);    }    //这个方法很鸡肋了,建议不看,是老版本用<property name="username" value="Jack"/>    //标签做依赖注入的代码实现,复杂且无用    if (pvs != null) {        applyPropertyValues(beanName, mbd, bw, pvs);    }}

SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区这里又会调用到AutowiredAnnotationBeanPostProceessor类的方法进行依赖注入。

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);    try {        metadata.inject(bean, beanName, pvs);    }    catch (BeanCreationException ex) {        throw ex;    }    catch (Throwable ex) {        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);    }    return pvs;}

通过前面的收集结果,我们知道了哪些属性获取方法有注解,那么在这里我们只要根据有注解的属性进行依赖注入就可以了,这里就不再赘述了。

2.3.4.2 dubbo的依赖注入
其实dubbo的依赖注入流程跟spring是一模一样的,也是借助BeanPostProcessor类型的接口来实现,只是这个类是ReferenceAnnotationBeanPostProcessor

OK,我们来一个示例:

public class Ioc {    @DubboReference    private UserService userService;    @PostConstruct    public void init() {        System.out.println(userService);    }}

也是两个步骤,只是这两个步骤是由ReferenceAnnotationBeanPostProcessor它来完成的。

1、@DubboReference注解收集

2、实例的依赖注入

1、@DubboReference注解收集

收集的逻辑跟spring是一模一样的,如图:SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区会走到ReferenceAnnotationBeanPostProcessor类中进行注解收集;

@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {    if (beanType != null) {        if (isReferenceBean(beanDefinition)) {            //mark property value as optional            List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();            for (PropertyValue propertyValue : propertyValues) {                propertyValue.setOptional(true);            }        } else if (isAnnotatedReferenceBean(beanDefinition)) {            // extract beanClass from java-config bean method generic return type:            ReferenceBean<DemoService>                //Class beanClass = getBeanFactory().getType(beanName);        } else {            //收集有@DubboReference注解的属性或者方法并封装成对象            AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType,null);            metadata.checkConfigMembers(beanDefinition);            try {                //这里是对每一个有@DubboReference注解的属性或者方法创建一个ReferenceBean的BeanDefinition对象,因为要完成服务的引用,必须要有@ReferenceBean的实例                prepareInjection(metadata);            } catch (Exception e) {                throw new IllegalStateException("Prepare dubbo reference injection element failed", e);            }        }    }}

prepareInjection(metadata);的核心代码贴一下:

RootBeanDefinition beanDefinition = new RootBeanDefinition();//这里就会创建ReferenceBean对象beanDefinition.setBeanClassName(ReferenceBean.class.getName());beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);// set attribute instead of property valuesbeanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()GenericBeanDefinition targetDefinition = new GenericBeanDefinition();targetDefinition.setBeanClass(interfaceClass);String id = (String) beanDefinition.getPropertyValues().get(ReferenceAttributes.ID);beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition,id+"_decorated"));// signal object type since Spring 5.2beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);

总结一下,收集注解会收集@DubboReference注解的属性或方法,然后还会创建跟@DubboReference对应的ReferenceBean对象,因为要完成代理的生成和服务的引用。

2、实例的依赖注入

@DubboReference属性的依赖注入,流程跟spring也是一样的,处理类是ReferenceAnnotationBeanPostProcessorSpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区会走到ReferenceAnnotationBeanPostProcessor类中的postProcessPropertyValues方法完成属性依赖注入

public PropertyValues postProcessPropertyValues(    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {    try {        //这里走缓存拿手机的结果        AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName,bean.getClass(), pvs);        //再次确定有没有生成Referencebean的BeanDefinition        prepareInjection(metadata);        //依赖注入        metadata.inject(bean, beanName, pvs);    } catch (BeansException ex) {        throw ex;    } catch (Throwable ex) {        throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName() + " dependencies is failed",ex);    }    return pvs;}
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {    //获取代理对象的核心方法    Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(),this);    //属性的方式注入    if (member instanceof Field) {        Field field = (Field) member;        ReflectionUtils.makeAccessible(field);        field.set(bean, injectedObject);    } else if (member instanceof Method) {        Method method = (Method) member;        ReflectionUtils.makeAccessible(method);        method.invoke(bean, injectedObject);    }}
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,AnnotatedInjectElement 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.put(cacheKey, injectedObject);    // }    // return injectedObject;    return doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);}
@Overrideprotected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,AnnotatedInjectElement injectedElement) throws Exception{    if (injectedElement.injectedObject == null) {        throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");    }    //getBean获取实例,id是 UserService    return getBeanFactory().getBean((String) injectedElement.injectedObject);}

SpringCloud Alibaba系列——5Dubbo整合spring(下)-鸿蒙开发者社区

前面创建了ReferenceBean对象,其中有一个ReferenceBean对象的id就是userService.所有这里getBean会获取到ReferenceBean的实例或者其FactoryBean的getObject返回的实例,其实ReferenceBean是有实现FactoryBean接口的,所有这里会返回getObject返回的实例,我们看看ReferenceBean。

public class ReferenceBean<T> implements FactoryBean<T>,ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean,DisposableBean    @Override    public T getObject() {    if (lazyProxy == null) {        createLazyProxy();    }    return (T) lazyProxy;}private void createLazyProxy() {    //set proxy interfaces    //see also:org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>,boolean)    //很明显这里会用spring的代理工厂生成代理对象    ProxyFactory proxyFactory = new ProxyFactory();    //定义哦了TargetSource类型实例,spring中会有该类调用其getTarget方法拿到目标对象,其实这里就会生成Dubbo的代理    proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());    proxyFactory.addInterface(interfaceClass);    Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();    for (Class<?> anInterface : internalInterfaces) {        proxyFactory.addInterface(anInterface);    }    if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {        //add service interface        try {            Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);            proxyFactory.addInterface(serviceInterface);        } catch (ClassNotFoundException e) {            // generic call maybe without service interface class locally        }    }    //返回spring的代理    this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);}
private class DubboReferenceLazyInitTargetSource extends AbstractLazyCreationTargetSource {    @Override    protected Object createObject() throws Exception {        return getCallProxy();    }    @Override    public synchronized Class<?> getTargetClass() {        return getInterfaceClass();    }}//父类的getTarget方法会被spring的advice调用到,又会回调子类的createObject方法,模板设计模式@Overridepublic synchronized Object getTarget() throws Exception {    if (this.lazyTarget == null) {        logger.debug("Initializing lazy target object");        this.lazyTarget = createObject();    }    return this.lazyTarget;}private Object getCallProxy() throws Exception {    if (referenceConfig == null) {        throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");    }    //get reference proxy    return referenceConfig.get();}

所以从这个流程看,@DubboReference依赖注入的对象其实就一个spring的代理对象,然后用这个代理对象调用的时候,最终会调到TargetSource对象的getTarget方法,由这个方法会调到referenceConfig.get()方法生成dubbo的代理对象,referenceConfig.get()这个方法也是引用dubbo服务的核心方法。

分类
已于2022-8-24 16:39:01修改
收藏
回复
举报
回复
    相关推荐