3.RPCフレームワークの簡単な実装(カスタムbeanの解析)

19800 ワード

xsdファイル、spring.ハンダーズとスプリングschemasファイルが定義されたら、次のように独自のNamespaceHandler処理クラスを定義します.
package com.lipenglong.ldubbo.config.spring.schema;

import com.lipenglong.ldubbo.config.ProtocolConfig;
import com.lipenglong.ldubbo.config.RegistryConfig;
import com.lipenglong.ldubbo.config.spring.ReferenceBean;
import com.lipenglong.ldubbo.config.spring.ServiceBean;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 *  Handler ,spring 
 * 
 * Created by lipenglong on 2017/7/21.
 */
public class LdubboNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        registerBeanDefinitionParser("protocol", new LdubboBeanDefinitionParser(ProtocolConfig.class));
        registerBeanDefinitionParser("service", new LdubboBeanDefinitionParser(ServiceBean.class));
        registerBeanDefinitionParser("registry", new LdubboBeanDefinitionParser(RegistryConfig.class));
        registerBeanDefinitionParser("reference", new LdubboBeanDefinitionParser(ReferenceBean.class));
    }
}

対ldubbo:protocol beanはProtocolConfigオブジェクト、ldubbo:registry beanはRegistryConfigオブジェクトとして解析されます.ldubbo:serviceおよびldubbo:referenceのbeanは、ServiceBeanおよびReferenceBeanオブジェクトとして解析されます.なぜconfigオブジェクトばかりではないのですか?protocolとregistryにとって構成されたbeanであり、簡単なJava pojoオブジェクトです.サービスおよびreferenceでは、構成だけでなく、springのいくつかのファクトリクラスを継承してbean初期化後の他の操作、すなわちサービスの露出および参照を実現する必要があるサービスおよび参照サービスも暴露されます.
上のLdubbo NamespaceHandlerクラスについては、configオブジェクト、beanオブジェクトはdubboソースコードの構造と一致しており、パケットパスも同様であり、ldubboはdubboを真似て書かれた簡単なrpc実装である.次に、LdubboBeanDefinitionParserクラスのxmlの具体的な解析の実装です.コードは以下の通りです.
package com.lipenglong.ldubbo.config.spring.schema;

import com.lipenglong.ldubbo.config.ProtocolConfig;
import com.lipenglong.ldubbo.config.RegistryConfig;
import com.lipenglong.ldubbo.config.spring.ServiceBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import java.lang.reflect.Method;

/**
 * ldubbo bean xml , spring 
 * 
 * Created by lipenglong on 2017/7/21.
 */
public class LdubboBeanDefinitionParser implements BeanDefinitionParser {
    private final Class> beanClass;

    public LdubboBeanDefinitionParser(Class> serviceBeanClass) {
        this.beanClass = serviceBeanClass;
    }

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        // bean id 
        String id = element.getAttribute("id");
        if (StringUtils.isEmpty(id)) {
            if (ServiceBean.class.equals(beanClass)) {
                id = element.getAttribute("interface");
            } else if (ProtocolConfig.class.equals(beanClass)) {
                id = element.getAttribute("name");
            } else {
                id = beanClass.getSimpleName();
            }
        }
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        beanDefinition.getPropertyValues().addPropertyValue("id", id);

        // class set , 
        for (Method method : beanClass.getMethods()) {
            String name = method.getName();
            if (name.length() > 3 && name.startsWith("set")) {
                String property = name.substring(3, 4).toLowerCase() + name.substring(4);
                String value = element.getAttribute(property);
                if (StringUtils.isEmpty(value)) {
                    if ("protocolConfig".equals(property)) {
                        for (String beanName : parserContext.getRegistry().getBeanDefinitionNames()) {
                            BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(beanName);
                            if (ProtocolConfig.class.getName().equals(definition.getBeanClassName())) {
                                beanDefinition.getPropertyValues().addPropertyValue(property, definition);
                            }
                        }
                    } else if ("registryConfig".equals(property)) {
                        for (String beanName : parserContext.getRegistry().getBeanDefinitionNames()) {
                            BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(beanName);
                            if (RegistryConfig.class.getName().equals(definition.getBeanClassName())) {
                                beanDefinition.getPropertyValues().addPropertyValue(property, definition);
                            }
                        }
                    }
                    continue;
                }
                Object reference;
                if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
                    reference = new RuntimeBeanReference(value);
                } else {
                    reference = value;
                }
                beanDefinition.getPropertyValues().addPropertyValue(property, reference);
            }
        }
        return beanDefinition;
    }
}

parseメソッドはxmlの構成をconfigオブジェクトとして解析し,まずidが付与されているか否かを判断し,xmlがidを構成していない場合はidを指定する.次にclassのsetメソッドを遍歴し、属性名propertyをelement.getAttribute(property)はxmlで構成されたvalueを取得し、valueに対して空ではなく、説明オブジェクト属性がxmlの属性であり、属性がrefであれば説明値が参照されるオブジェクトであり、springコンテキストにこのbeanがある場合、valueをnew RuntimeBeanReference(value)オブジェクトに設定する.
最初のspringプロファイルで約束されたldubboプロファイルをレビューします.
<ldubbo:protocol name="ldubbo"/>
<ldubbo:service interface="com.lipenglong.ldubbo.api.service.UserService" ref="userService"/>

<ldubbo:registry address="127.0.0.1:30880" protocol="ldubbo"/>
<ldubbo:reference interface="com.lipenglong.ldubbo.api.service.UserService" id="userService"/>

中身はldubbo:service refが参照オブジェクトに対応しているほか、Stringタイプです.
ProtocolConfigオブジェクト定義:
package com.lipenglong.ldubbo.config;

/**
 * protocol 
 * 
 * Created by lipenglong on 2017/7/25.
 */
public class ProtocolConfig extends AbstractConfig {
    private static final long serialVersionUID = -5067525426300152084L;
    //  
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "ProtocolConfig{" +
                "name='" + name + '\'' +
                '}';
    }
}

RegistryConfigオブジェクト定義:
package com.lipenglong.ldubbo.config;

/**
 * registry 
 * 
 * Created by lipenglong on 2017/8/30.
 */
public class RegistryConfig extends AbstractConfig {
    private static final long serialVersionUID = -128869717961737215L;
    private String address;
    private String protocol;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getRegistryIp() {
        return address.substring(0, address.indexOf(":"));
    }

    public int getRegistryPort() {
        return Integer.parseInt(address.substring(address.indexOf(":") + 1));
    }

    @Override
    public String toString() {
        return "RegistryConfig{" +
                "address='" + address + '\'' +
                ", protocol='" + protocol + '\'' +
                '}';
    }
}

addressプロパティはxmlに記入されたipとポートのため、getRegistryIp()とgetRegistryPort()の2つの方法でipアドレスとポート構成をそれぞれ取得します.
configオブジェクトクラスはAbstractConfigクラスを継承しています.これは自分で定義した親クラスで、id属性を持っています.AbstractConfigクラスは以下のように定義されています.
package com.lipenglong.ldubbo.config;

import java.io.Serializable;

/**
 * ldubbo config 
 * 
 * Created by lipenglong on 2017/7/25.
 */
public abstract class AbstractConfig implements Serializable {
    private static final long serialVersionUID = 4408739851966423744L;
    protected String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

ServiceBeanオブジェクトとReferenceBeanオブジェクトについては、それぞれServiceConfigオブジェクトとReferenceConfigオブジェクトを継承します.これらの定義は上記のconfigオブジェクトと似ています.次に、露出サービスのServiceBeanクラスの具体的な実装について書きます.