3.RPCフレームワークの簡単な実装(カスタムbeanの解析)
19800 ワード
xsdファイル、spring.ハンダーズとスプリングschemasファイルが定義されたら、次のように独自のNamespaceHandler処理クラスを定義します.
対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の具体的な解析の実装です.コードは以下の通りです.
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:service refが参照オブジェクトに対応しているほか、Stringタイプです.
ProtocolConfigオブジェクト定義:
RegistryConfigオブジェクト定義:
addressプロパティはxmlに記入されたipとポートのため、getRegistryIp()とgetRegistryPort()の2つの方法でipアドレスとポート構成をそれぞれ取得します.
configオブジェクトクラスはAbstractConfigクラスを継承しています.これは自分で定義した親クラスで、id属性を持っています.AbstractConfigクラスは以下のように定義されています.
ServiceBeanオブジェクトとReferenceBeanオブジェクトについては、それぞれServiceConfigオブジェクトとReferenceConfigオブジェクトを継承します.これらの定義は上記のconfigオブジェクトと似ています.次に、露出サービスのServiceBeanクラスの具体的な実装について書きます.
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クラスの具体的な実装について書きます.