3.RPC框架的简单实现(解析自定义bean)
来源:互联网 发布:仿小米商城源码 编辑:程序博客网 时间:2024/06/05 17:40
xsd文件,spring.handlers和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框架的调用入口 * <p/> * 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对象。对service和reference来说不仅是配置,还要暴露服务和引用服务,它们需要继承spring的一些工厂类,来实现bean初始化后的其它操作即服务的暴露和引用。
关于上面LdubboNamespaceHandler类,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容器 * <p/> * 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配置类 * <p/> * 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配置类 * </p> * 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()两个方法分别获取ip地址和端口配置。
config对象类都继承了AbstractConfig类,这个是自己定义的父类,拥有id属性,AbstractConfig类定义如下:
package com.lipenglong.ldubbo.config;import java.io.Serializable;/** * ldubbo config配置父类 * <p/> * 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类的具体实现。
- 3.RPC框架的简单实现(解析自定义bean)
- 一个简单的rpc框架的实现
- 一个简单的rpc框架的实现
- 最简单的Rpc框架的实现
- 简单的RPC框架的实现
- 一个简单的rpc框架实现(一)
- 5.RPC框架的简单实现(SPI机制-ProtocolFactory)
- 使用Akka实现一个简单的RPC框架(一)
- 使用Akka实现一个简单的RPC框架(二)
- Zookeeper实现简单的分布式RPC框架
- Java实现简单的RPC框架
- 利用zookeeper实现简单的RPC框架
- 最简单的RPC框架实现
- java实现简单的RPC框架
- Java实现简单的RPC框架
- Java实现简单的RPC框架
- 简单的RPC框架实现-转载
- 自己实现一个简单的RPC框架
- 傅里叶变换理解
- Android所有权限
- jupyter notebook 精华
- mysql主从
- JEESZ-SSO解决方案
- 3.RPC框架的简单实现(解析自定义bean)
- 正则表达式用法基础及应用实例
- 微信推出热搜排行榜,微博压力山大?
- 深浅拷贝
- mybatis call stored procedure(MyBatis 调用存储过程)
- 【勤哲应用】用Excel服务器做银行综合管理系统
- HDU2048 神、上帝以及老天爷(错排)
- ABAP小写金额转大写
- JavaScript函数使用要点