motan源碼分析三:與spring框架的結合

在本文第一章,分析的demo中使用了代碼加載的方式加載了相關的類,但在咱們的實際工做中,使用spring來加載相關的類的狀況會更多,本文將分析一下motan是如何與spring一塊兒協同工做的,主要的原理就是利用了spring支持的自定義標籤的實現,這也是須要和spring結合的框架的實現方式。java

1.首先實現motan.xsd文件,具體能夠參見:http://api.weibo.com/schema/motan.xsdnode

2.對於標籤的相應解析類進行註冊:spring

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:api

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方法
        }
    }

}

總結一下本章的知識點:ide

1.使用常規的spring擴展自定義標籤的方式來實現motan對於spring的支持;ui

2.集成NamespaceHandlerSupport來實現標籤解析類的註冊;this

3.實現BeanDefinitionParser的接口來解析具體的標籤;spa

4.在配置信息加載完後,利用onApplicationEvent事件來調用export方法來發布服務。code

相關文章
相關標籤/搜索