自己实现dubbo服务的导出

1.今天 我们要实现dubbo的三个功能:

  1. dubbo标签的定义
  2. dubbo标签的解析并赋值给对应的XXConfig(如:ServiceConfig 对应dubbo:service 标签)
  3. 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 解析  标签执行
 * 
 * @author HadLuo
 * @since JDK1.7
 * @history 2018年5月2日 新建
 */
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        //  标签
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationBean.class));
         //  标签
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryBean.class));
        //  标签
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolBean.class));
        //  标签
        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 applicationHolder;
    /***holder 注入, 复杂对象****/
    @Tag(holder = ProtocolBean.class)
    private Holder 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 applicationHolder) {
        this.applicationHolder = applicationHolder;
    }

    public void setProtocolHolder(Holder 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

你可能感兴趣的:(自己写的框架)