This is the 8th day of my participation in the August Text Challenge.More challenges in August

>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…

A. The preface

The scanning logic of Dubbo Reference is similar to that of DubboService

2. Scanning process

2.1 Application Cases

public class DemoServiceComponent implements DemoService {

    @DubboReference
    private DemoService demoService;

    @Override
    public String sayHello(String name) {
        returndemoService.sayHello(name); }}Copy the code

2.2 Scanning of DubboReference

How does a Client create a proxy class for the @dubboReference interface

2.2.1 Reference Indicates the starting point of the scan

// The starting point of the Reference scan is DubboBootstrap, which contains this code
public DubboBootstrap start(a) {

    / /...
    
    // Initiate Refer Services processing
    referServices();
    
    / /...
     
}


private void referServices(a) {
    if (cache == null) {
        cache = ReferenceConfigCache.getCache();
    }

    // 2.2.2: The reference in configManager is scanned previously
    configManager.getReferences().forEach(rc -> {
        
        // Set the container for it, and refreshReferenceConfig<? > referenceConfig = (ReferenceConfig<? >) rc; referenceConfig.setBootstrap(this);
        if(! referenceConfig.isRefreshed()) { referenceConfig.refresh(); }/ /... I don't care about the logic
    });
}
Copy the code

CacheManager parameter details

2.2.2 Scanning process of References

How can References be scanned

Step 1: Spring management time creation

In this part, the corresponding class of Bean initialization, the starting point and the Reference is the ReferenceAnnotationBeanPostProcessor postProcessPropertyValues for processing

@Override
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

   
    AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
    prepareInjection(metadata);
    // bean: DemoServiceComponent is the previous bean entity class
    // beanName : demoServiceComponent
    metadata.inject(bean, beanName, pvs);
  
    return pvs;
}
Copy the code

Let’s look at the structure of metadata:

Step 2: Reflection of member variables

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    
    // Get the member variable, which is the @dubboReference object
    Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);

    // TODO: See later here
    if (member instanceof Field) {
        Field field = (Field) member;
        ReflectionUtils.makeAccessible(field);
        field.set(bean, injectedObject);
    } else if (member instanceofMethod) { Method method = (Method) member; ReflectionUtils.makeAccessible(method); method.invoke(bean, injectedObject); }}Copy the code

Get the injected Bean here

// 
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class
        injectedType, AnnotatedInjectElement injectedElement) throws Exception {
                                   
    // injectedElement.injectedObject -> demoService
    return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
Copy the code

Step 3: Main process of reference processing

The MBD obtained by the getBean createBean is the ReferenceBean

C- ReferenceBean
public void afterPropertiesSet(a) throws Exception {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // INTERFACE_CLASS -> interfaceClass -> 
        // INTERFACE_NAME -> interfaceName
        
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());
        this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
        this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
        
        // Constants.REFERENCE_PROPS -> referenceProps
        if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {
            // @DubboReference annotation at java-config class @Bean method
            // @DubboReference annotation at reference field or setter method
            As you can see, JavaConfig classes and properties are supported, as well as Setter injection
            referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);
        } else {
            // Here is how different registration types are handled
            if (beanDefinition instanceof AnnotatedBeanDefinition) {
                // Return ReferenceBean in java-config class @Bean method
                ReferenceBeanSupport.convertReferenceProps(referenceProps, interfaceClass);
                if (this.interfaceName == null) {
                    this.interfaceName = (String) referenceProps.get(ReferenceAttributes.INTERFACE); }}else {
                // xml reference beanpropertyValues = beanDefinition.getPropertyValues(); }}// -> BEAN_NAME = "dubboReferenceBeanManager";
        ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
        referenceBeanManager.addReference(this);
    }
Copy the code

Step 4: Management process of Reference

// C- ReferenceBeanManager
public void addReference(ReferenceBean referenceBean) throws Exception {
    String referenceBeanName = referenceBean.getId();

    PropertyResolver propertyResolver = applicationContext.getEnvironment();

    String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, propertyResolver);
    
    ReferenceBean oldReferenceBean = referenceIdMap.get(referenceBeanName);
    // There is a detail here, pass! = Judge, but! = compares address references, not objects like equal
    // The object address is different, which means that the Bean is created duplicate, meaning that the same instance cannot be created
    if(oldReferenceBean ! =null) {
        if(referenceBean ! = oldReferenceBean) { String oldReferenceKey = ReferenceBeanSupport.generateReferenceKey(oldReferenceBean, propertyResolver);throw new IllegalStateException("Found duplicated ReferenceBean with id: " + referenceBeanName +
                    ", old: " + oldReferenceKey + ", new: " + referenceKey);
        }
        return;
    }
    
    // private Map<String, ReferenceBean> referenceIdMap = new ConcurrentHashMap<>();
    // This is an object that points to the ReferenceBean by id/name
    referenceIdMap.put(referenceBeanName, referenceBean);
    //save cache, map reference key to referenceBeanName
    this.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);

    // if add reference after prepareReferenceBeans(), should init it immediately.
    if(initialized) { initReferenceBean(referenceBean); }}Copy the code

With the ReferenceBean, the ReferenceConfig object is then created, which will later become the base configuration object for invoke

private synchronized void  initReferenceBean(ReferenceBean referenceBean) throws Exception {

    if(referenceBean.getReferenceConfig() ! =null) {
        return;
    }

    // reference key -> ReferenceBean:org.apache.dubbo.demo.DemoService()
    String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext.getEnvironment());

    ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);
    if (referenceConfig == null) {
        // Create the actual ReferenceConfig object using the ReferenceCreator
        // Here we get the attributes in the annotation
        Map<String, Object> referenceAttributes = ReferenceBeanSupport.getReferenceAttributes(referenceBean);
        referenceConfig = ReferenceCreator.create(referenceAttributes, applicationContext)
                .defaultInterfaceClass(referenceBean.getObjectType())
                .build();

        // If not the generated name, set the ID
        if(referenceBean.getId() ! =null && !referenceBean.getId().contains("#")) {
            referenceConfig.setId(referenceBean.getId());
        }

        // cache referenceConfig
        // private Map
      
        referenceConfigMap = new ConcurrentHashMap<>();
      ,>
        referenceConfigMap.put(referenceKey, referenceConfig);

        // register ReferenceConfig -> Step 5
        DubboBootstrap.getInstance().reference(referenceConfig);
    }

    // associate referenceConfig to referenceBean
    referenceBean.setKeyAndReferenceConfig(referenceKey, referenceConfig);
}
Copy the code

Now that the comments are complete and the process is clear, let’s look at the logic for caching

Step 5: Config Manager management


public DubboBootstrap reference(ReferenceConfig
        referenceConfig) {
    // Set the container
    referenceConfig.setBootstrap(this);
    
      
    // Use XML format, I guess it should be saved with the old version, will it be convenient to upgrade?
    configManager.addReference(referenceConfig);
    return this;
}

// call below
public void addReference(ReferenceConfigBase
        referenceConfig) 
protected <T extends AbstractConfig> T addConfig(AbstractConfig config, boolean unique) {
   
   // omit null logic
    return (T) write(() -> {
        Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> newMap());
        return addIfAbsent(config, configsMap, unique);
    });
}

Copy the code

Step 6: Use

It is already in the Cache where it was retrieved in the first place. How is this handled?

3. Supplementary details

3.1 Creation of ReferenceBean

Here, when getBean is reflected, ReferenceBean is reflected, which is actually the relevant logic of Spring IOC

TODO: A little bit more, let’s write a chapter and see how Dubbo brings Spring to life!!

conclusion

Next we will see how a Reference object is converted to an Invoke object