private static RootBeanDefinition parse()

in dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java [97:284]


    private static RootBeanDefinition parse(
            Element element, ParserContext parserContext, Class<?> beanClass, boolean registered) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        if (ServiceBean.class.equals(beanClass)) {
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        }
        // config id
        String configId = resolveAttribute(element, "id", parserContext);
        if (StringUtils.isNotEmpty(configId)) {
            beanDefinition.getPropertyValues().addPropertyValue("id", configId);
        }

        String configName = "";
        // get configName from name
        if (StringUtils.isEmpty(configId)) {
            configName = resolveAttribute(element, "name", parserContext);
        }

        String beanName = configId;
        if (StringUtils.isEmpty(beanName)) {
            // generate bean name
            String prefix = beanClass.getName();
            int counter = 0;
            beanName = prefix + (StringUtils.isEmpty(configName) ? "#" : ("#" + configName + "#")) + counter;
            while (parserContext.getRegistry().containsBeanDefinition(beanName)) {
                beanName = prefix + (StringUtils.isEmpty(configName) ? "#" : ("#" + configName + "#")) + (counter++);
            }
        }
        beanDefinition.setAttribute(BEAN_NAME, beanName);

        if (ProtocolConfig.class.equals(beanClass)) {
            //            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
            //                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
            //                PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
            //                if (property != null) {
            //                    Object value = property.getValue();
            //                    if (value instanceof ProtocolConfig && beanName.equals(((ProtocolConfig)
            // value).getName())) {
            //                        definition.getPropertyValues().addPropertyValue("protocol", new
            // RuntimeBeanReference(beanName));
            //                    }
            //                }
            //            }
        } else if (ServiceBean.class.equals(beanClass)) {
            String className = resolveAttribute(element, "class", parserContext);
            if (StringUtils.isNotEmpty(className)) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                parseProperties(element.getChildNodes(), classDefinition, parserContext);
                beanDefinition
                        .getPropertyValues()
                        .addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, beanName + "Impl"));
            }
        }

        Map<String, Class> beanPropTypeMap = beanPropsCache.get(beanClass.getName());
        if (beanPropTypeMap == null) {
            beanPropTypeMap = new HashMap<>();
            beanPropsCache.put(beanClass.getName(), beanPropTypeMap);
            if (ReferenceBean.class.equals(beanClass)) {
                // extract bean props from ReferenceConfig
                getPropertyMap(ReferenceConfig.class, beanPropTypeMap);
            } else {
                getPropertyMap(beanClass, beanPropTypeMap);
            }
        }

        ManagedMap parameters = null;
        Set<String> processedProps = new HashSet<>();
        for (Map.Entry<String, Class> entry : beanPropTypeMap.entrySet()) {
            String beanProperty = entry.getKey();
            Class type = entry.getValue();
            String property = StringUtils.camelToSplitName(beanProperty, "-");
            processedProps.add(property);
            if ("parameters".equals(property)) {
                parameters = parseParameters(element.getChildNodes(), beanDefinition, parserContext);
            } else if ("methods".equals(property)) {
                parseMethods(beanName, element.getChildNodes(), beanDefinition, parserContext);
            } else if ("arguments".equals(property)) {
                parseArguments(beanName, element.getChildNodes(), beanDefinition, parserContext);
            } else {
                String value = resolveAttribute(element, property, parserContext);
                if (StringUtils.isNotBlank(value)) {
                    value = value.trim();
                    if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
                        RegistryConfig registryConfig = new RegistryConfig();
                        registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
                        // see AbstractInterfaceConfig#registries, It will be invoker setRegistries method when
                        // BeanDefinition is registered,
                        beanDefinition.getPropertyValues().addPropertyValue("registries", registryConfig);
                        // If registry is N/A, don't init it until the reference is invoked
                        beanDefinition.setLazyInit(true);
                    } else if ("provider".equals(property)
                            || "registry".equals(property)
                            || ("protocol".equals(property)
                                    && AbstractServiceConfig.class.isAssignableFrom(beanClass))) {
                        /**
                         * For 'provider' 'protocol' 'registry', keep literal value (should be id/name) and set the value to 'registryIds' 'providerIds' protocolIds'
                         * The following process should make sure each id refers to the corresponding instance, here's how to find the instance for different use cases:
                         * 1. Spring, check existing bean by id, see{@link ServiceBean#afterPropertiesSet()}; then try to use id to find configs defined in remote Config Center
                         * 2. API, directly use id to find configs defined in remote Config Center; if all config instances are defined locally, please use {@link org.apache.dubbo.config.ServiceConfig#setRegistries(List)}
                         */
                        beanDefinition.getPropertyValues().addPropertyValue(beanProperty + "Ids", value);
                    } else {
                        Object reference;
                        if (isPrimitive(type)) {
                            value = getCompatibleDefaultValue(property, value);
                            reference = value;
                        } else if (ONRETURN.equals(property) || ONTHROW.equals(property) || ONINVOKE.equals(property)) {
                            int index = value.lastIndexOf(".");
                            String ref = value.substring(0, index);
                            String method = value.substring(index + 1);
                            reference = new RuntimeBeanReference(ref);
                            beanDefinition.getPropertyValues().addPropertyValue(property + METHOD, method);
                        } else if (EXECUTOR.equals(property)) {
                            reference = new RuntimeBeanReference(value);
                        } else {
                            if ("ref".equals(property)
                                    && parserContext.getRegistry().containsBeanDefinition(value)) {
                                BeanDefinition refBean =
                                        parserContext.getRegistry().getBeanDefinition(value);
                                if (!refBean.isSingleton()) {
                                    throw new IllegalStateException(
                                            "The exported service ref " + value + " must be singleton! Please set the "
                                                    + value + " bean scope to singleton, eg: <bean id=\"" + value
                                                    + "\" scope=\"singleton\" ...>");
                                }
                            }
                            reference = new RuntimeBeanReference(value);
                        }
                        if (reference != null) {
                            beanDefinition.getPropertyValues().addPropertyValue(beanProperty, reference);
                        }
                    }
                }
            }
        }

        NamedNodeMap attributes = element.getAttributes();
        int len = attributes.getLength();
        for (int i = 0; i < len; i++) {
            Node node = attributes.item(i);
            String name = node.getLocalName();
            if (!processedProps.contains(name)) {
                if (parameters == null) {
                    parameters = new ManagedMap();
                }
                String value = node.getNodeValue();
                parameters.put(name, new TypedStringValue(value, String.class));
            }
        }
        if (parameters != null) {
            beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
        }

        // post-process after parse attributes
        if (ProviderConfig.class.equals(beanClass)) {
            parseNested(
                    element, parserContext, ServiceBean.class, true, "service", "provider", beanName, beanDefinition);
        } else if (ConsumerConfig.class.equals(beanClass)) {
            parseNested(
                    element,
                    parserContext,
                    ReferenceBean.class,
                    true,
                    "reference",
                    "consumer",
                    beanName,
                    beanDefinition);
        } else if (ReferenceBean.class.equals(beanClass)) {
            configReferenceBean(element, parserContext, beanDefinition, null);
        } else if (MetricsConfig.class.equals(beanClass)) {
            parseMetrics(element, parserContext, beanDefinition);
        }

        // register bean definition
        if (parserContext.getRegistry().containsBeanDefinition(beanName)) {
            throw new IllegalStateException("Duplicate spring bean name: " + beanName);
        }

        if (registered) {
            parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
        return beanDefinition;
    }