Поговорим о Dubbo (4): основной исходный код — врезка в Spring

задняя часть Spring Element Dubbo

1 способ настройки даббо

  1. Конфигурация XML: механизм расширения на основе схемы и XML, реализация Spring;
  2. конфигурация свойства: загрузить dubbo.properties в корневой каталог пути к классам;
  3. Конфигурация API: Настроить с помощью жесткого кодирования (устарело);
  4. Конфигурация аннотации: настроить по аннотации (поддерживается Dubbo-2.5.7 и выше, не рекомендуется);

1.1 Конфигурация недвижимости

законфигурация свойствапуть, черезПеременные среды, параметры запуска -D для указания dubbo.propertiesфайл, порядок загрузки файлов следующий:

  1. -D параметр запуска;
  2. Переменные среды;
  3. корневой каталог classpath;

конфигурация свойствакод загрузкиConfigUtils.javaследующее:

public static final String DUBBO_PROPERTIES_KEY = "dubbo.properties.file";
public static final String DEFAULT_DUBBO_PROPERTIES = "dubbo.properties";

private static volatile Properties PROPERTIES;

/**
 * 属性配置加载逻辑
 */
public static Properties getProperties() {
    if (PROPERTIES == null) {
        synchronized (ConfigUtils.class) {
            if (PROPERTIES == null) {
                // 1. -D 启动参数
                String path = System.getProperty(Constants.DUBBO_PROPERTIES_KEY);
                if (path == null || path.length() == 0) {
                    // 2. 环境变量
                    path = System.getenv(Constants.DUBBO_PROPERTIES_KEY);
                    if (path == null || path.length() == 0) {
                        // 3. classpath 根目录
                        path = Constants.DEFAULT_DUBBO_PROPERTIES;
                    }
                }
                PROPERTIES = ConfigUtils.loadProperties(path, false, true);
            }
        }
    }
    return PROPERTIES;
}

2 Расширение схемы Dubbo

Как упоминалось в начале статьи,Метод конфигурации Dubbo XML реализован на основе Spring Schema и механизма расширения XML.. С помощью этого механизма мы можем написать нашу собственную схему,И настройте Bean в соответствии с пользовательским тегом пользовательской схемы..

Существует несколько шагов для использования механизма расширения Spring XML:

  1. Определить схему (записать файл .xsd);
  2. определить JavaBean;
  3. Написать NamespaceHandler и BeanDefinitionParser Pull Parsing схемы;
  4. Напишите файлы spring.handlers и spring.schemas для последовательного анализа частей;
  5. Применить конфигурацию в файле XML;

2.1 Определение схемы

Определение схемы отражено в файле .xsd,Файлы расположены в подмодуле dubbo-config-spring.:

dubbo.xsd

2.2 определяется JavaBean

JavaBeans, соответствующие всем тегам Dubbo, определяются в подмодуле dubbo-config-api., свойства в JavaBean соответствуют элементам конфигурации тега один за другим:

Dubbo标签对应的JavaBean

2.3 Схема разбора

В качестве примера возьмем конфигурацию в следующем XML-файле Spring:

<context:component-scan base-package="com.demo.dubbo.server.serviceimpl"/>
<context:property-placeholder location="classpath:config.properties"/>
<tx:annotation-driven transaction-manager="transactionManager"/>

Как Spring разрешает эти конфигурации? Что, если мы хотим определить нашу собственную конфигурацию?? Приведенная выше конфигурация XML разделена на три части:

  1. пространство имен, такие как tx, контекст
  2. элемент элемент, такие как сканирование компонентов, заполнитель свойств, управление аннотациями
  3. атрибут атрибут, такие как базовый пакет, местоположение, менеджер транзакций

Spring определяет два интерфейса, чтобы разрешить вышеперечисленное:

  1. NamespaceHandler: зарегистрированы куча BeanDefinitionParser, и они используются для анализа;
  2. BeanDefinitionParser: используется для анализа содержимого каждого элемента;

Давайте рассмотрим конкретный случай,Возьмите пространство имен контекста Spring в качестве примера, соответствующееNamespaceHandlerреализацияContextNamespaceHandler:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}

Прописал кучу beandefinitionParser, если мы хотим увидетьcomponent-scanКак этого добиться, вы можете увидеть в соответствующемComponentScanBeanDefinitionParserисходный код.

Если вы настраиваете NamespaceHandler, как добавить его в Spring?По умолчанию Spring загрузит файл META-INF/spring.handlers в пакете jar, чтобы найти NamespaceHandler., файл Spring по умолчанию выглядит следующим образом:

META-INF/spring.handlers

spring.handlersСодержимое файла выглядит следующим образом: Соответствующее пространство имен использует соответствующий NamespaceHandler.

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

в то же время,Весенний абонементspring.schemasдокументы, такие какcontextСхема тегаcontext.xsdи используйте его для проверки формата XML-файла конфигурации приложения.. Содержимое файла spring.schemas выглядит следующим образом:

http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd
http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd
http\://www.springframework.org/schema/context/spring-context-4.0.xsd=org/springframework/context/config/spring-context-4.0.xsd
http\://www.springframework.org/schema/context/spring-context-4.1.xsd=org/springframework/context/config/spring-context-4.1.xsd
http\://www.springframework.org/schema/context/spring-context-4.2.xsd=org/springframework/context/config/spring-context-4.2.xsd
http\://www.springframework.org/schema/context/spring-context-4.3.xsd=org/springframework/context/config/spring-context-4.3.xsd
http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-4.3.xsd
......

Расположение файлов следующее:

spring.handlers&spring.schemas文件

Когда среда Spring инициализируется, она загружает все файлы spring.handlers из пути к классам и сохраняет сопоставление между URL-адресом пространства имен и обработчиком пространства имен в карте. -Встроенный IOC (в пространстве имен bean-компонентов).Для тегов процессор пространства имен будет искаться на этой карте, и этот пользовательский процессор будет использоваться для разбора тегов. допустимыйDefaultBeanDefinitionDocumentReaderиBeanDefinitionParserDelegateСм. код соответствующей логики в классе:

 // org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.java
 /**
  * Parse the elements at the root level in the document:
  * "import", "alias", "bean".
  * @param root the DOM root element of the document
  */
  protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate); //解析默认标签
                    }
                    else {
                        delegate.parseCustomElement(ele); //解析自定义标签
                    }
                }
            }
    }
    else {
         delegate.parseCustomElement(root);
    }
 }

 // org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.java
 public BeanDefinition parseCustomElement(Element ele) {
     return parseCustomElement(ele, null);
 }

 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
     String namespaceUri = getNamespaceURI(ele);
     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
     if (handler == null) {
         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
         return null;
     }
     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
 }

3 Анализ схемы Даббо

В качестве примера возьмем следующую конфигурацию Spring для Dubbo Provider:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
      xmlns="http://www.springframework.org/schema/beans"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://code.alibabatech.com/schema/dubbo
      http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="demo-provider"/>
    <!-- 使用multicast广播注册中心暴露服务地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234"/>
    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880"/>
    
    <dubbo:reference id="registryService" interface="com.alibaba.dubbo.registry.RegistryService">
        <property name=” check” value=” false”/>
    </dubbo:reference>
    <!-- 和本地bean一样实现服务 -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>
    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>
</beans>

3.1 Определение bean-компонента преобразования XML

Схема может быть расширена в соответствии с Spring, давайте сначалаdubbo.jarвнутриMETA-INF/spring.handlersСодержание конфигурации:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

Начнем с этого класса (DubboNamespaceHandler) давай сделаем это,DubboNamespaceHandlerКод:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    static {
        // 确保系统中只存在一份解析处理器类定义
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }
    public void init() {
        // DubboBeanDefinitionParser定义了如何解析dubbo节点信息
        // DubboBeanDefinitionParser的第一个参数是beanclass
        // 配置<dubbo:application>标签解析器
	registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        // 配置<dubbo:module>标签解析器
	registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        //配置<dubbo:registry>标签解析器
	registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        //配置<dubbo:monitor>标签解析器
	registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        //配置<dubbo:provider>标签解析器
	registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        //配置<dubbo:consumer>标签解析器
	registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        //配置<dubbo:protocol>标签解析器
	registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
	//配置<dubbo:service>标签解析器
	registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
	//配置<dubbo:refenrence>标签解析器
	registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
	//配置<dubbo:annotation>标签解析器
	registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }
}

Согласно механизму, предоставленному Spring,Dubbo связывает каждый настроенный элемент и соответствующий парсер. Настоящую ответственность за анализ содержимого, объявленного в файле конфигурации, в соответствующее beandefinition (форму, которую можно представить в виде bean-компонента) несет класс DubbobeAndefinitionParser.Parse., Все теги dubbo анализируются единообразно с помощью DubboBeanDefinitionParser, и на основе однозначного сопоставления атрибутов теги XML анализируются в объекты Bean. Конкретный код выглядит следующим образом:

/** 
 * 解析dubbo自定义标签,往BeanDefinition设置属性值,这个时候bean还没有创建 
 * @param element 
 * @param parserContext 
 * @param beanClass 
 * @param required 
 * @return 
 */  
@SuppressWarnings("unchecked")  
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {  
    RootBeanDefinition beanDefinition = new RootBeanDefinition();  
    beanDefinition.setBeanClass(beanClass);  
    // 设置懒加载为false,表示立即加载,spring启动时,立刻进行实例化  
    // 如果设置为true,那么要第一次向容器通过getBean索取bean时实例化,在spring bean的配置里可以配置  
    // 这里会设置懒加载为false,其实还可以得到一个推断就是dubbo标签创建的bean就是单例bean(singleton bean)  
    // 因为lazy-init的设置只对singleton bean有效,对原型bean(prototype无效)  
    beanDefinition.setLazyInit(false);  
    String id = element.getAttribute("id");  
    // 如果没有设置bean的id  
    if ((id == null || id.length() == 0) && required) {  
        String generatedBeanName = element.getAttribute("name");  
        // 如果name没有配置  
        if (generatedBeanName == null || generatedBeanName.length() == 0) {  
            // 如果是ProtocolConfig类型,bean name默认为 dubbo,其他的为配置的interface值  
            if (ProtocolConfig.class.equals(beanClass)) {  
                generatedBeanName = "dubbo";  
            } else {  
                generatedBeanName = element.getAttribute("interface");  
            }  
        }  
        /* 
         * 如果generatedBeanName仍为null,那么取 beanClass 的名字,beanClass 其实就是要解析的类型
         * 如:com.alibaba.dubbo.config.ApplicationConfig 
         */  
        if (generatedBeanName == null || generatedBeanName.length() == 0) {  
            generatedBeanName = beanClass.getName();  
        }  
        //如果id没有设置,那么 id = generatedBeanName,如果是ProtocolConfig类型的话,自然就是 dubbo  
        id = generatedBeanName;   
        int counter = 2;  
        /* 
         * 由于spring的bean id不能重复,但有些标签可能会配置多个如:dubbo:registry 
         * 所以 id 在后面加数字 2、3、4 区分 
         */  
        while(parserContext.getRegistry().containsBeanDefinition(id)) {  
            id = generatedBeanName + (counter ++);  
        }  
    }  
    if (id != null && id.length() > 0) {  
        // 检查是否有 bean id 相同的  
        if (parserContext.getRegistry().containsBeanDefinition(id))  {  
            throw new IllegalStateException("Duplicate spring bean id " + id);  
        }  
        /* 
         * 注册 bean 定义 
         * org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition 
         * 会按照 id 即beanName做一些检查,判断是否重载已加载过的bean等等 
         * 跟到代码里其实 bean 的注册也是放到 ConcurrentHashMap 里 
         * beanName也就是这里的 id 会放到 list 里 
         */  
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);  
        // 给bean添加属性值  
        beanDefinition.getPropertyValues().addPropertyValue("id", id);  
    }  
    if (ProtocolConfig.class.equals(beanClass)) { //解析<dubbo:protocol
        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 && id.equals(((ProtocolConfig) value).getName())) {
                    // RuntimeBeanReference:这个的类的主要作用是根据bean名称返回bean实例的引用,避免客户端显示获取bean实例;  
                    definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));  
                }  
            }  
        }  
    } else if (ServiceBean.class.equals(beanClass)) { // 解析<dubbo:service  
        String className = element.getAttribute("class");// 获取类全名  
        if(className != null && className.length() > 0) {  
            RootBeanDefinition classDefinition = new RootBeanDefinition();  
            // 通过反射获取类  
            classDefinition.setBeanClass(ReflectUtils.forName(className));  
            classDefinition.setLazyInit(false);  
            /* 
             *   解析子节点,有些配置可能是: 
             *   <dubbo:service interface="com.alihealth.dubbo.api.drugInfo.service.DemoService" executes="10"> 
             *       <property name="ref" ref="demoService"></property> 
             *       <property name="version" value="1.0.0"></property> 
             *   </dubbo:service> 
             */  
            parseProperties(element.getChildNodes(), classDefinition);  
            /* 
             *   ref直接设置成了 接口名 + Impl 的bean
             */  
            beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));  
        }  
    } else if (ProviderConfig.class.equals(beanClass)) {  
        /* 
         *   <dubbo:provider 为缺省配置 ,所以在解析的时候,如果<dubbo:service有些值没配置,那么会用<dubbo:provider值进行填充 
         */  
        parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);  
    } else if (ConsumerConfig.class.equals(beanClass)) {  
        /* 
         * 同上 
         */  
        parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);  
    }

    Set<String> props = new HashSet<String>();  
    ManagedMap parameters = null;  
    for (Method setter : beanClass.getMethods()) {  
        String name = setter.getName();  
        // 给model注入值时,如ServiceConfig,方法必须是set开头,并且参数数量只能为1  
        if (name.length() > 3 && name.startsWith("set")  
                && Modifier.isPublic(setter.getModifiers())  
                && setter.getParameterTypes().length == 1) {  
            // 方法参数类型,因为参数只能是1,所以直接取[0]  
            Class<?> type = setter.getParameterTypes()[0];  
            // 根据set方法名获取属性值,如:setListener 得到的属性为:listener  
            String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");  
            props.add(property);  
            Method getter = null;  
            try {  
                getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);  
            } catch (NoSuchMethodException e) {  
                try {  
                    getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);  
                } catch (NoSuchMethodException e2) {  
                }  
            }  
            if (getter == null   
                    || ! Modifier.isPublic(getter.getModifiers())  
                    || ! type.equals(getter.getReturnType())) {  
                continue;  
            }  

            if ("parameters".equals(property)) {  
                /* 
                 * 如果属性为 parameters,如ProtocolConfig里的setParameters(Map<String, String> parameters) 
                 * 那么去子节点获取 <dubbo:parameter 
                 * <dubbo:protocol name="dubbo" host="127.0.0.1" port="9998" accepts="1000"  > 
                 *    <dubbo:parameter key="adsf" value="adf" /> 
                 *    <dubbo:parameter key="errer" value="aerdf" /> 
                 * </dubbo:protocol> 
                 */  
                parameters = parseParameters(element.getChildNodes(), beanDefinition);  
            } else if ("methods".equals(property)) {  
                /* 
                 *  解析 <dubbo:method 并设置 methods 值 --ServiceConfig中 
                 */  
                parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);  
            } else if ("arguments".equals(property)) {  
                /* 
                 *   同上 ,解析<dubbo:argument --- MethodConfig中 
                 */  
                parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);  
            } else {  
                String value = element.getAttribute(property);  
                if (value != null) {  
                    value = value.trim();  
                    if (value.length() > 0) {  
                        // 不发布到任何注册中心时 registry = "N/A"  
                        if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {  
                            RegistryConfig registryConfig = new RegistryConfig();  
                            registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);  
                            beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);  
                        } else if ("registry".equals(property) && value.indexOf(',') != -1) {  
                            // 多注册中心用 , 号分隔  
                            parseMultiRef("registries", value, beanDefinition, parserContext);  
                        } else if ("provider".equals(property) && value.indexOf(',') != -1) {  
                            parseMultiRef("providers", value, beanDefinition, parserContext);  
                        } else if ("protocol".equals(property) && value.indexOf(',') != -1) {  
                            // 同上 多协议暴露  
                            parseMultiRef("protocols", value, beanDefinition, parserContext);  
                        } else {  
                            Object reference;  
                            if (isPrimitive(type)) {//如果参数类型为 java 的基本类型  
                                if ("async".equals(property) && "false".equals(value)  
                                        || "timeout".equals(property) && "0".equals(value)  
                                        || "delay".equals(property) && "0".equals(value)  
                                        || "version".equals(property) && "0.0.0".equals(value)  
                                        || "stat".equals(property) && "-1".equals(value)  
                                        || "reliable".equals(property) && "false".equals(value)) {  
                                  /* 
                                   * 兼容旧版本xsd中的default值,以上配置的值在xsd中有配置defalt值 
                                   * <xsd:attribute name="version" type="xsd:string" use="optional" default="0.0.0"> 
                                  */  
                                    value = null;  
                                }  
                                reference = value;  
                            } else if ("protocol".equals(property)  
                                    // 如果属性为 protocol 那么要判断protocol对应的拓展点配置有没有  
                                    && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value)  
                                    // 检查当前使用的协议是否已经解析过 可能在这里被解析过<dubbo:protocol name="dubbo"  
                                    && (! parserContext.getRegistry().containsBeanDefinition(value)  
                                            || ! ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {  
                                if ("dubbo:provider".equals(element.getTagName())) {  
                                    logger.warn("Recommended replace <dubbo:provider protocol=\"" + value + "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />");  
                                }  
                                // 兼容旧版本配置  
                                ProtocolConfig protocol = new ProtocolConfig();  
                                protocol.setName(value);  
                                reference = protocol;  
                            } else if ("monitor".equals(property)  
                                    // 同上  
                                    && (! parserContext.getRegistry().containsBeanDefinition(value)  
                                            || ! MonitorConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {  
                                // 兼容旧版本配置  
                                reference = convertMonitor(value);  
                            } else if ("onreturn".equals(property)) {  
                                // 回调方法 类似onSuccess  
                                int index = value.lastIndexOf(".");  
                                // bean的名字  
                                String returnRef = value.substring(0, index);  
                                String returnMethod = value.substring(index + 1);  
                                reference = new RuntimeBeanReference(returnRef);  
                                beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);  
                            } else if ("onthrow".equals(property)) {  
                                // 回调 异常执行的方法 ,类似 onError  
                                int index = value.lastIndexOf(".");  
                                String throwRef = value.substring(0, index);  
                                String throwMethod = value.substring(index + 1);  
                                reference = new RuntimeBeanReference(throwRef);  
                                beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);  
                            } else {  
                                if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {  
                                    BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);  
                                    /* 
                                     *  必须是单例bean(singleton),原型bean(prototype)不行,sevice初始化一次,在spring容器里也只有一个 实例 
                                     *  是不是和dubbo的幂等有关,如果为原型bean,那么服务就变成有状态的了 
                                     */  
                                    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);  
                            }  
                            /* 
                             *  设置属性,值为另外一个关联的bean 
                             *  RuntimeBeanReference 固定占位符类,当在beanfactory中作为另外一个bean的引用时,作为属性值对象,将在运行时进行解析 
                             */  
                            beanDefinition.getPropertyValues().addPropertyValue(property, 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 (! props.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);  
    }  
    return beanDefinition;  
}

@SuppressWarnings("unchecked")  
private static void parseMultiRef(String property, String value, RootBeanDefinition beanDefinition,  
        ParserContext parserContext) {  
    // 解析 registries 、providers、protocols 时支持多引用  
    String[] values = value.split("\\s*[,]+\\s*");  
    ManagedList list = null;  
    for (int i = 0; i < values.length; i++) {  
        String v = values[i];  
        if (v != null && v.length() > 0) {  
            if (list == null) {  
                list = new ManagedList();  
            }  
            list.add(new RuntimeBeanReference(v));  
        }  
    }  
    beanDefinition.getPropertyValues().addPropertyValue(property, list);  
}  

private static void parseNested(Element element, ParserContext parserContext, Class<?> beanClass,  
                                 boolean required, String tag, String property, String ref, BeanDefinition beanDefinition) {  
     NodeList nodeList = element.getChildNodes();  
     if (nodeList != null && nodeList.getLength() > 0) {  
         boolean first = true;  
         for (int i = 0; i < nodeList.getLength(); i++) {  
             Node node = nodeList.item(i);  
             if (node instanceof Element) {  
                 if (tag.equals(node.getNodeName())  
                         || tag.equals(node.getLocalName())) {  
                     if (first) {  
                         first = false;  
                         String isDefault = element.getAttribute("default");  
                         /* 
                          *  如果 <dubbo:provider 标签没有配置default开关,那么直接设置 default = "false" 
                          *  这样做的目的是为了让 <dubbo:provider里的配置都只是 <dubbo:service 或 <dubbo:reference的默认或缺省配置 
                          */  
                         if (isDefault == null || isDefault.length() == 0) {  
                             beanDefinition.getPropertyValues().addPropertyValue("default", "false");  
                         }  
                     }  
                     BeanDefinition subDefinition = parse((Element) node, parserContext, beanClass, required);  
                     if (subDefinition != null && ref != null && ref.length() > 0) {  
                         subDefinition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(ref));  
                     }  
                 }  
             }  
         }  
     }  
 }

private static void parseProperties(NodeList nodeList, RootBeanDefinition beanDefinition) {  
    if (nodeList != null && nodeList.getLength() > 0) {  
        for (int i = 0; i < nodeList.getLength(); i++) {  
            Node node = nodeList.item(i);  
            if (node instanceof Element) {  
                // 如果是 <property 元素  
                if ("property".equals(node.getNodeName())  
                        || "property".equals(node.getLocalName())) {  
                    String name = ((Element) node).getAttribute("name");  
                    if (name != null && name.length() > 0) {  
                        String value = ((Element) node).getAttribute("value");  
                        // 获取 ref  
                        String ref = ((Element) node).getAttribute("ref");  
                        if (value != null && value.length() > 0) {  
                            beanDefinition.getPropertyValues().addPropertyValue(name, value);  
                        } else if (ref != null && ref.length() > 0) {  
                            beanDefinition.getPropertyValues().addPropertyValue(name, new RuntimeBeanReference(ref));  
                        } else {  
                            /* 
                             *   只支持两种property的设置方法: 
                             *   <property  ref="" name=""> 
                             *   <property  value="" name=""> 
                             */  
                            throw new UnsupportedOperationException("Unsupported <property name=\"" + name + "\"> sub tag, Only supported <property name=\"" + name + "\" ref=\"...\" /> or <property name=\"" + name + "\" value=\"...\" />");  
                        }  
                    }  
                }  
            }  
        }  
    }  
}  

@SuppressWarnings("unchecked")  
private static ManagedMap parseParameters(NodeList nodeList, RootBeanDefinition beanDefinition) {  
    if (nodeList != null && nodeList.getLength() > 0) {  
        ManagedMap parameters = null;  
        for (int i = 0; i < nodeList.getLength(); i++) {  
            Node node = nodeList.item(i);  
            if (node instanceof Element) {  
                // 解析 <dubbo:parameter  
                if ("parameter".equals(node.getNodeName())  
                        || "parameter".equals(node.getLocalName())) {  
                    if (parameters == null) {  
                        parameters = new ManagedMap();  
                    }  
                    String key = ((Element) node).getAttribute("key");  
                    String value = ((Element) node).getAttribute("value");  
                    boolean hide = "true".equals(((Element) node).getAttribute("hide"));  
                    if (hide) {  
                        key = Constants.HIDE_KEY_PREFIX + key;  
                    }  
                    // 添加参数,String 类型  
                    parameters.put(key, new TypedStringValue(value, String.class));  
                }  
            }  
        }  
        return parameters;  
    }  
    return null;  
}  

@SuppressWarnings("unchecked")  
private static void parseMethods(String id, NodeList nodeList, RootBeanDefinition beanDefinition,  
                          ParserContext parserContext) {  
    if (nodeList != null && nodeList.getLength() > 0) {  
        ManagedList methods = null;  
        for (int i = 0; i < nodeList.getLength(); i++) {  
            Node node = nodeList.item(i);  
            if (node instanceof Element) {  
                Element element = (Element) node;  
                // <dubbo:method  
                if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) {  
                    String methodName = element.getAttribute("name");  
                    if (methodName == null || methodName.length() == 0) {  
                        throw new IllegalStateException("<dubbo:method> name attribute == null");  
                    }  
                    if (methods == null) {  
                        methods = new ManagedList();  
                    }  
                    // 解析 <dubbo:method MethodConfig  
                    BeanDefinition methodBeanDefinition = parse(((Element) node),  
                            parserContext, MethodConfig.class, false);  
                    String name = id + "." + methodName;  
                    BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(  
                            methodBeanDefinition, name);  
                    methods.add(methodBeanDefinitionHolder);  
                }  
            }  
        }  
        if (methods != null) {  
            beanDefinition.getPropertyValues().addPropertyValue("methods", methods);  
        }  
    }  
}  

Конечной целью синтаксического анализа является возврат объекта RootBeanDefinition, который содержит всю проанализированную информацию о компоненте., Обратите внимание, что после синтаксического анализа bean-компонента Spring просто преобразует его в абстрактную структуру объекта данных внутри Spring.Создание (создание экземпляра) bean-компонента создается при первом вызове getBean..

3.2 Преобразование beanDefinition Bean

Процесс преобразования beanDefinition bean-компонентов на самом деле выполняется Spring, эта часть принадлежит Spring.На следующем рисунке примерно показано, как компонент инициализируется внутри Spring:

Spring获取Bean实例