zoukankan      html  css  js  c++  java
  • motan源码分析三:与spring框架的结合

    在本文第一章,分析的demo中使用了代码加载的方式加载了相关的类,但在我们的实际工作中,使用spring来加载相关的类的情况会更多,本文将分析一下motan是如何与spring一起协同工作的,主要的原理就是利用了spring支持的自定义标签的实现,这也是需要和spring结合的框架的实现方式。

    1.首先实现motan.xsd文件,具体可以参见:http://api.weibo.com/schema/motan.xsd

    2.对于标签的相应解析类进行注册:

    public class MotanNamespaceHandler extends NamespaceHandlerSupport {//集成NamespaceHandlerSupport类,spring会自动调用init方法
        public final static Set<String> protocolDefineNames = new ConcurrentHashSet<String>();
        public final static Set<String> registryDefineNames = new ConcurrentHashSet<String>();
        public final static Set<String> basicServiceConfigDefineNames = new ConcurrentHashSet<String>();
        public final static Set<String> basicRefererConfigDefineNames = new ConcurrentHashSet<String>();
    
        @Override
        public void init() {//标记注册
            registerBeanDefinitionParser("referer", new MotanBeanDefinitionParser(RefererConfigBean.class, false));
            registerBeanDefinitionParser("service", new MotanBeanDefinitionParser(ServiceConfigBean.class, true));
            registerBeanDefinitionParser("protocol", new MotanBeanDefinitionParser(ProtocolConfig.class, true));
            registerBeanDefinitionParser("registry", new MotanBeanDefinitionParser(RegistryConfig.class, true));
            registerBeanDefinitionParser("basicService", new MotanBeanDefinitionParser(BasicServiceInterfaceConfig.class, true));
            registerBeanDefinitionParser("basicReferer", new MotanBeanDefinitionParser(BasicRefererInterfaceConfig.class, true));
            registerBeanDefinitionParser("spi", new MotanBeanDefinitionParser(SpiConfigBean.class, true));
        }
    }

    3.motan的标签解析类MotanBeanDefinitionParser:

    public class MotanBeanDefinitionParser implements BeanDefinitionParser {//实现BeanDefinitionParser接口
    
        private final Class<?> beanClass;
    
        private final boolean required;
    
        public MotanBeanDefinitionParser(Class<?> beanClass, boolean required) {
            this.beanClass = beanClass;
            this.required = required;
        }
    
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            try {
                return parse(element, parserContext, beanClass, required);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        @SuppressWarnings({"rawtypes", "unchecked"})
        private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required)
                throws ClassNotFoundException {
            RootBeanDefinition bd = new RootBeanDefinition();
            bd.setBeanClass(beanClass);
            // 不允许lazy init
            bd.setLazyInit(false);
    
            // 如果没有id则按照规则生成一个id,注册id到context中
            String id = element.getAttribute("id");
            if ((id == null || id.length() == 0) && required) {
                String generatedBeanName = element.getAttribute("name");
                if (generatedBeanName == null || generatedBeanName.length() == 0) {
                    generatedBeanName = element.getAttribute("class");
                }
                if (generatedBeanName == null || generatedBeanName.length() == 0) {
                    generatedBeanName = beanClass.getName();
                }
                id = generatedBeanName;
                int counter = 2;
                while (parserContext.getRegistry().containsBeanDefinition(id)) {
                    id = generatedBeanName + (counter++);
                }
            }
            if (id != null && id.length() > 0) {
                if (parserContext.getRegistry().containsBeanDefinition(id)) {
                    throw new IllegalStateException("Duplicate spring bean id " + id);
                }
                parserContext.getRegistry().registerBeanDefinition(id, bd);
            }
            bd.getPropertyValues().addPropertyValue("id", id);
            if (ProtocolConfig.class.equals(beanClass)) {
                MotanNamespaceHandler.protocolDefineNames.add(id);
    
            } else if (RegistryConfig.class.equals(beanClass)) {
                MotanNamespaceHandler.registryDefineNames.add(id);
    
            } else if (BasicServiceInterfaceConfig.class.equals(beanClass)) {
                MotanNamespaceHandler.basicServiceConfigDefineNames.add(id);
    
            } else if (BasicRefererInterfaceConfig.class.equals(beanClass)) {
                MotanNamespaceHandler.basicRefererConfigDefineNames.add(id);
    
            } else if (ServiceConfigBean.class.equals(beanClass)) {
                String className = element.getAttribute("class");
                if (className != null && className.length() > 0) {
                    RootBeanDefinition classDefinition = new RootBeanDefinition();
                    classDefinition.setBeanClass(Class.forName(className, true, Thread.currentThread().getContextClassLoader()));
                    classDefinition.setLazyInit(false);
                    parseProperties(element.getChildNodes(), classDefinition);
                    bd.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
                }
            }
    
            Set<String> props = new HashSet<String>();
            ManagedMap parameters = null;
            // 把配置文件中的可以set的属性放到bd中
            for (Method setter : beanClass.getMethods()) {
                String name = setter.getName();
                // 必须是setXXX
                if (name.length() <= 3 || !name.startsWith("set") || !Modifier.isPublic(setter.getModifiers())
                        || setter.getParameterTypes().length != 1) {
                    continue;
                }
                String property = (name.substring(3, 4).toLowerCase() + name.substring(4)).replaceAll("_", "-");
                props.add(property);
                if ("id".equals(property)) {
                    bd.getPropertyValues().addPropertyValue("id", id);
                    continue;
                }
                String value = element.getAttribute(property);
                if (StringUtils.isBlank(value) && "protocol".equals(property)) {
                    // srevice中的protocol信息是隐含在export中,所以需要从export中获取protocol来配置
                    String exportValue = element.getAttribute(URLParamType.export.getName());
                    if (!StringUtils.isBlank(exportValue)) {
                        value = ConfigUtil.extractProtocols(exportValue);
                    }
                }
                if ("methods".equals(property)) {
                    parseMethods(id, element.getChildNodes(), bd, parserContext);
                }
                if (StringUtils.isBlank(value)) {
                    continue;
                }
                value = value.trim();
                if (value.length() == 0) {
                    continue;
                }
                Object reference;
                if ("ref".equals(property)) {
                    if (parserContext.getRegistry().containsBeanDefinition(value)) {
                        BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
                        if (!refBean.isSingleton()) {
                            throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value
                                    + " bean scope to singleton, eg: <bean id="" + value + "" scope="singleton" ...>");
                        }
                    }
                    reference = new RuntimeBeanReference(value);
                } else if ("protocol".equals(property)) {
                    if (!value.contains(",")) {
                        reference = new RuntimeBeanReference(value);
                    } else {
                        parseMultiRef("protocols", value, bd, parserContext);
                        reference = null;
                    }
                } else if ("registry".equals(property)) {
                    parseMultiRef("registries", value, bd, parserContext);
                    reference = null;
                } else if ("basicService".equals(property)) {
                    reference = new RuntimeBeanReference(value);
    
                } else if ("basicReferer".equals(property)) {
                    reference = new RuntimeBeanReference(value);
    
                } else if ("extConfig".equals(property)) {
                    reference = new RuntimeBeanReference(value);
                } else {
                    reference = new TypedStringValue(value);
                }
    
                if (reference != null) {
                    bd.getPropertyValues().addPropertyValue(property, reference);
                }
            }
            if (ProtocolConfig.class.equals(beanClass)) {
                // 把剩余的属性放到protocol的parameters里面
                NamedNodeMap attributes = element.getAttributes();
                int len = attributes.getLength();
                for (int i = 0; i < len; i++) {
                    Node node = attributes.item(i);
                    String name = node.getLocalName();
                    if (!props.contains(name)) {
                        if (parameters == null) {
                            parameters = new ManagedMap();
                        }
                        String value = node.getNodeValue();
                        parameters.put(name, new TypedStringValue(value, String.class));
                    }
                }
                bd.getPropertyValues().addPropertyValue("parameters", parameters);
            }
            return bd;
        }
    
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static void parseMultiRef(String property, String value, RootBeanDefinition beanDefinition, ParserContext parserContext) {
            String[] values = value.split("\s*[,]+\s*");
            ManagedList list = null;
            for (int i = 0; i < values.length; i++) {
                String v = values[i];
                if (v != null && v.length() > 0) {
                    if (list == null) {
                        list = new ManagedList();
                    }
                    list.add(new RuntimeBeanReference(v));
                }
            }
            beanDefinition.getPropertyValues().addPropertyValue(property, list);
        }
    
        private static void parseProperties(NodeList nodeList, RootBeanDefinition beanDefinition) {
            if (nodeList != null && nodeList.getLength() > 0) {
                for (int i = 0; i < nodeList.getLength(); i++) {
                    Node node = nodeList.item(i);
                    if (node instanceof Element) {
                        if ("property".equals(node.getNodeName()) || "property".equals(node.getLocalName())) {
                            String name = ((Element) node).getAttribute("name");
                            if (name != null && name.length() > 0) {
                                String value = ((Element) node).getAttribute("value");
                                String ref = ((Element) node).getAttribute("ref");
                                if (value != null && value.length() > 0) {
                                    beanDefinition.getPropertyValues().addPropertyValue(name, value);
                                } else if (ref != null && ref.length() > 0) {
                                    beanDefinition.getPropertyValues().addPropertyValue(name, new RuntimeBeanReference(ref));
                                } else {
                                    throw new UnsupportedOperationException("Unsupported <property name="" + name
                                            + ""> sub tag, Only supported <property name="" + name + "" ref="..." /> or <property name=""
                                            + name + "" value="..." />");
                                }
                            }
                        }
                    }
                }
            }
        }
    
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static void parseMethods(String id, NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext)
                throws ClassNotFoundException {
            if (nodeList != null && nodeList.getLength() > 0) {
                ManagedList methods = null;
                for (int i = 0; i < nodeList.getLength(); i++) {
                    Node node = nodeList.item(i);
                    if (node instanceof Element) {
                        Element element = (Element) node;
                        if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) {
                            String methodName = element.getAttribute("name");
                            if (methodName == null || methodName.length() == 0) {
                                throw new IllegalStateException("<motan:method> name attribute == null");
                            }
                            if (methods == null) {
                                methods = new ManagedList();
                            }
                            BeanDefinition methodBeanDefinition = parse((Element) node, parserContext, MethodConfig.class, false);
                            String name = id + "." + methodName;
                            BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(methodBeanDefinition, name);
                            methods.add(methodBeanDefinitionHolder);
                        }
                    }
                }
                if (methods != null) {
                    beanDefinition.getPropertyValues().addPropertyValue("methods", methods);
                }
            }
        }
    
    }

    4.在第一章节中,有一个export的动作在各项配置加载完成后,需要被调用,motan是通过下面的ServiceConfigBean类来实现的:

    public class ServiceConfigBean<T> extends ServiceConfig<T>
            implements
                BeanPostProcessor,
                BeanFactoryAware,
                InitializingBean,
                DisposableBean,
                ApplicationListener<ContextRefreshedEvent> {
    
    
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            if (!getExported().get()) {
                export();//当配置信息加载完后,调用export方法
            }
        }
    
    }
    

    总结一下本章的知识点:

    1.使用常规的spring扩展自定义标签的方式来实现motan对于spring的支持;

    2.集成NamespaceHandlerSupport来实现标签解析类的注册;

    3.实现BeanDefinitionParser的接口来解析具体的标签;

    4.在配置信息加载完后,利用onApplicationEvent事件来调用export方法来发布服务。

  • 相关阅读:
    数据绑定
    快速上手小程序云开发
    微信小程序敏捷开发实战
    测试驱动开发实践4————testSave之新增文档分类
    测试驱动开发实践3————从testList开始
    测试驱动开发实践2————测试驱动开发之前
    测试驱动开发实践1————项目代码生成
    构建微服务开发环境8————Hello 微服务
    构建微服务开发环境7————使用Github管理项目代码的版本
    构建微服务开发环境6————利用npm安装前端框架
  • 原文地址:https://www.cnblogs.com/mantu/p/5882323.html
Copyright © 2011-2022 走看看