在本文第一章,分析的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>();@Overridepublic 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;}@Overridepublic 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 initbd.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();// 必须是setXXXif (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方法来发布服务。