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类来实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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方法来发布服务。
分类:
motan源码分析
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?