在本文第一章,分析的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方法来发布服务。