编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

motan源码分析三:与spring框架的结合

wxchong 2024-08-18 00:38:57 开源技术 14 ℃ 0 评论

在本文第一章,分析的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));
 registerBeanDefinitionParser("annotation", new MotanBeanDefinitionParser(AnnotationBean.class, true));
 Initializable initialization = InitializationFactory.getInitialization();
 initialization.init();
 }
}

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方法来发布服务。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表