1.今天 我们要实现dubbo的三个功能:
dubbo标签的定义dubbo标签的解析并赋值给对应的XXConfig(如:ServiceConfig 对应dubbo:service 标签)dubbo怎么利用spring bean的生命周期来进行导出 dubbo:service 服务 的2.代码实现 总所周知,spring提供让我们自定义标签的功能(不懂的,自己google),dubbo是这样使用它的: 建立三个文件 (文件内容,后面会提供下载): src/META-INF/dubbo.xsd src/META-INF/spring.handlers src/META-INF/spring.schemas
spring初始化自定义标签会回调NamespaceHandlerSupport的 init方法
/*** * spring 解析 <dubbo:> 标签执行 * * @author HadLuo * @since JDK1.7 * @history 2018年5月2日 新建 */ public class DubboNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { // <dubbo:application> 标签 registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationBean.class)); // <dubbo:registry> 标签 registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryBean.class)); // <dubbo:protocol> 标签 registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolBean.class)); // <dubbo:service> 标签 registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class)); } }DubboBeanDefinitionParser 解析器,spring会自动调用parse方法
public class DubboBeanDefinitionParser implements BeanDefinitionParser { private Class<?> beanClass; private static final DubboIdStrategy ID_STRATEGY = new DubboIdStrategy(); public DubboBeanDefinitionParser(Class<?> beanClass) { this.beanClass = beanClass; } @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 动态注入 spring bean RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(beanClass); beanDefinition.setLazyInit(false); String id = element.getAttribute("id"); if (id == null || id.isEmpty()) { // dubbo标签中没有id属性的 , 生成一个不重复的id id = IdGenerator.generateId(ID_STRATEGY, beanClass); } if (parserContext.getRegistry().containsBeanDefinition(id)) { // spring 有这个id 的bean 了 直接抛出异常 throw new IllegalStateException("Duplicate spring bean id " + id); } // 将 dubbo标签bean 注入spring parserContext.getRegistry().registerBeanDefinition(id, beanDefinition); // 为 dubbo标签bean设置属性值 , 这里不同于dubbo源码(源码太繁琐了), 这里直接 用反射 设置基本类型值,利用holder来设置 属性为 dubbo bean对象 的值 for (Field field : ReflectUtils.getAllFieldsByAnnotation(beanClass, Tag.class)) { String tag = field.getAnnotation(Tag.class).value(); Class<?> holderClass = field.getAnnotation(Tag.class).holder(); beanDefinition.getPropertyValues().addPropertyValue(field.getName(), getValueByType(field, element.getAttribute(tag),holderClass)); } return beanDefinition; } /*** * 设置字段值 * * @param field * @param target * @param val * @throws NumberFormatException * @throws IllegalArgumentException * @throws IllegalAccessException * @author HadLuo 2018年4月13日 新建 */ @SuppressWarnings("rawtypes") private static Object getValueByType(Field field, String val,Class<?> holderClass) { if (val == null) { return null; } if (field.getType().equals(Integer.class) || field.getType().equals(int.class)) { return Integer.parseInt(val); } else if (field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)) { return Boolean.parseBoolean(val); } else if (field.getType().equals(Byte.class) || field.getType().equals(byte.class)) { return Byte.parseByte(val); } else if (field.getType().equals(Character.class) || field.getType().equals(char.class)) { return val.charAt(0); } else if (field.getType().equals(Double.class) || field.getType().equals(double.class)) { return Double.parseDouble(val); } else if (field.getType().equals(Float.class) || field.getType().equals(float.class)) { return Float.parseFloat(val); } else if (field.getType().equals(Long.class) || field.getType().equals(long.class)) { return Long.parseLong(val); } else if (field.getType().equals(Short.class) || field.getType().equals(short.class)) { return Short.parseShort(val); } else if (field.getType().equals(String.class)) { return val; } else if (ReflectUtils.isChild(field.getType(), Holder.class)) { // 代表 是 对象 类型 , 从spring里面 找 String id = ID_STRATEGY.getFixBeanId(holderClass); if (id == null || id.isEmpty()) { throw new UnsupportedOperationException(field.getType().getName() + " 不能赋值为 :" + val); } // 用holder来 占位 , 后面初始化时 ,直接 利用spring context根据id来找dubbo bean return new Holder(id); } throw new UnsupportedOperationException(field.getType().getName() + " 不能赋值为 :" + val); } }ServiceBean 实现了spring bean的几个生命周期方法,同时继承了 ServiceConfig (service标签的配置值)
public class ServiceBean extends ServiceConfig implements SpringBeanLifecycle { // 是否已经导出 ServiceBean 服务 private transient boolean exported; @Override public void onApplicationEvent(ApplicationEvent event) { if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) { if (exported) { return; } setExported(true); export(); } } @Override public void afterPropertiesSet() throws Exception { System.err.println("spring init " + ServiceBean.class.getName() + " bean"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { registerApplicationContext(applicationContext); } @Override public void setBeanName(String name) { } public synchronized void setExported(boolean exported) { this.exported = exported; } public synchronized boolean exported() { return exported; } @Override public void destroy() throws Exception { setApplicationContext(null); setExported(false); } }ServiceConfig 配置信息类(包括实现导出)。
public class ServiceConfig extends AbstractConfig { /** 服务接口全路径 Tag注解,是我自己实现的 不同于dubbo*/ @Tag("interface") private String _interface; /** 服务对象实现引用 */ @Tag("ref") private String ref; /** 远程服务调用超时时间(毫秒) */ @Tag("timeout") private long timeout = 1000; /** 负载均衡策略,可选值为:random(随机)、roundrobin(轮询)、leastactive(最少活跃调用) */ @Tag("loadbalance") private String loadbalance = "random"; /** 是否缺省异步执行,不可靠的异步,只是忽略返回值,不阻塞执行线程 */ @Tag("async") private boolean async = false; /***holder 注入, 复杂对象****/ @Tag(holder = ApplicationBean.class) private Holder<ApplicationBean> applicationHolder; /***holder 注入, 复杂对象****/ @Tag(holder = ProtocolBean.class) private Holder<ProtocolBean> protocolHolder; public String getInterface() { return _interface; } public String getRef() { return ref; } public long getTimeout() { return timeout; } public String getLoadbalance() { return loadbalance; } public boolean isAsync() { return async; } public void set_interface(String _interface) { this._interface = _interface; } public void setRef(String ref) { this.ref = ref; } public void setTimeout(long timeout) { this.timeout = timeout; } public void setAsync(boolean async) { this.async = async; } public void setApplicationHolder(Holder<ApplicationBean> applicationHolder) { this.applicationHolder = applicationHolder; } public void setProtocolHolder(Holder<ProtocolBean> protocolHolder) { this.protocolHolder = protocolHolder; } public void setLoadbalance(String loadbalance) { this.loadbalance = loadbalance; } // dubbo://10.112.6.12:20880/cn.javacoder.test.dubbo.IHelloWorldService?application=test-provider // &dubbo=2.5.3&interface=cn.javacoder.test.dubbo.IHelloWorldService&methods=say&pid=6816&side=provider×tamp=1522284835101 public void export() { if (getApplicationContext() == null) { throw new RuntimeException("spring 还没有初始化完成"); } wakeupHolder(); // 这里 模拟 ====================== String url = "dubbo://" + "10.112.6.12:" + protocolHolder.get().getPort() + _interface + "?" + "application=" + applicationHolder.get().getName() + "&dubbo=2.5.3&interface=" + _interface + "&methods=say&pid=6816&side=provider×tamp=1522284835101"; System.err.println("准备开始 导出 >>" + url); } private void wakeupHolder() { // 利用spring context 根据id 来找 dubbo bean标签 applicationHolder.setValue(getApplicationContext()); protocolHolder.setValue(getApplicationContext()); } }以上 就是 dubbo 简单的 service标签 的 查找和 导出,与dubbo源码实现思想基本一致,上面没有贴出工程源码,可以加我qq : 657455400 或者 自行下载:https://download.csdn.net/download/luozheng4698729/10387658