Motan是新浪于2016年开源的一个RPC框架,类似的已有的RPC框架有像阿里开源的Dubbo,还有后来在此基础上做二次开源的当当网的dubbox。
Motan分为服务提供方和服务调用方,服务提供方发布服务,服务调用方调用服务。
看这样一个简单的例子:
1、创建一个接口,并且简单实现:

public interface FooService {public String hello(String name);
}
public class FooServiceImpl implements FooService {public String hello(String name) {System.out.println("Invoke RPC service method, "+name);return "Hello, "+name;}
}

2、配置xm

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:motan="http://api.weibo.com/schema/motan"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd"><bean id="serviceImpl" class="quickstart.FooServiceImpl" /><motan:registry address="127.0.0.1:2181" regProtocol="zookeeper" name="myzk"></motan:registry><motan:service interface="quickstart.FooService" ref="serviceImpl" registry="myzk" group="myMotanService1" export="8080"/></beans>

xml的配置也很简单易懂:
先定义一个id为serviceImpl的类,也就是我们的服务具体实现,然后将服务声明为zookeeper协议,并且注册到本地2181端口上,最后将服务实现发布成服务,暴露的端口为8080.
3、启动本地zk,端口默认为2181.运行服务器程序:

public class ServerZK {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:motanServer.xml");MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER,true);System.out.println("Server start...");}
}

运行输出信息:Server start…
服务发布成功了吗?可以使用zkClient查看目录:
/motan/myMotanService1/quickstart.FooService/server
发现有可用服务:
[192.168.0.6:8080]
运行main方法之后,这发生了什么?
观察我们的xml配置,有两点值得说明:
1、该xml使用了名为【motan】的Namespace
2、bean和registry的配置都被使用在了service配置中
对于第一点,由于是和Spring结合使用,所以motan命名空间肯定是会有相关联的NamespaceHandler进行解析的,也一定可以在motan的jar包中找到对应的xsd约束(在motan-core.jar包中就可以找到)。
根据一个不成文的约定(很多命名空间都是这样的,像Spring自带的aop命名空间,解析的Handler就是AOPNamespaceHandler),查找MotanNamespaceHandler类。
这个类负责来解析xml到Motan所需要使用到的类,具体过程很繁琐而无味。

service被解析成了ServiceConfigBean这个类,查看这个类,发现它的方法签名:

public class ServiceConfigBean<T> extends ServiceConfig<T>implementsBeanPostProcessor,BeanFactoryAware,InitializingBean,DisposableBean,ApplicationListener<ContextRefreshedEvent> 

实现了Spring暴露的扩展接口。
最后一个是ApplicationListener,这个类使得我们的ServiceConfigBean类监听了Spring的ContextRefreshEvent,在ApplicationContext加载时(此处是ClasspathXmlApplicationContext)的finishRefresh方法触发监听器,调用ServiceConfigBean的onApplicationEvent方法。
可以看到,这个方法调用了export方法,也就是发布服务的方法。

========分割线==========
实现InitializingBean的类,需要实现方法:

public void afterPropertiesSet() throws Exception {// 注意:basicConfig需要首先配置,因为其他可能会依赖于basicConfig的配置checkAndConfigBasicConfig();checkAndConfigExport();checkAndConfigRegistry();// 等spring初始化完毕后,再export服务// export();}

三个方法调用,分别加载了basicService;
checkAndConfigExport检查是否有export配置(如果没有,则用basicService中配置的export配置);
checkAndConfigRegistry保证发布的服务能有合适的registry,如果service配置了就使用该配置,如果没有,则取basicService中配置的,如果basicService中没有配置则从MotanNamespaceHandler.registryDefineNames中去加载(以防没有成功生成对象),如果以上的操作都没有获取到,则使用默认的local配置。

讲了这么一堆,现在才刚刚开始进入本节的主题,终于要开始发布服务了。

public void onApplicationEvent(ContextRefreshedEvent event) {if (!getExported().get()) {export();}}

每个ServiceConfigBean都有一个exported布尔值,表示该Service是不是已经被发布过。如果发布过,就不再发布。
接下来进入发布的方法,export():

public synchronized void export() {//在同步块中再次检查是不是已经被发布过了//此处的exported变量是J.C.U包中的原子变量,可以保证在多个线程之间及时可见if (exported.get()) {LoggerUtil.warn(String.format("%s has already been expoted, so ignore the export request!", interfaceClass.getName()));return;}//① 检查 方法是不是在接口中存在checkInterfaceAndMethods(interfaceClass, methods);//② 加载注册地址列表List<URL> registryUrls = loadRegistryUrls();if (registryUrls == null || registryUrls.size() == 0) {throw new IllegalStateException("Should set registry config for service:" + interfaceClass.getName());}//③ 生成协议和端口的键值对Map<String, Integer> protocolPorts = getProtocolAndPort();for (ProtocolConfig protocolConfig : protocols) {Integer port = protocolPorts.get(protocolConfig.getId());if (port == null) {throw new MotanServiceException(String.format("Unknow port in service:%s, protocol:%s", interfaceClass.getName(),protocolConfig.getId()));}// ④ 在注册的地址上,按协议和端口 进行服务发布doExport(protocolConfig, port, registryUrls);}//⑤ 发布之后的一些操作afterExport();}

几个主要的步骤都被抽成方法,嗯,所以这个方法看上去还是挺简洁易懂的。
1、检查方法是不是在接口中存在
由于moton发布service的时候可以指定的方法,所以需要在export之前,确认指定的接口是不是存在该方法。

2、生成注册地址列表

protected List<URL> loadRegistryUrls() {List<URL> registryList = new ArrayList<URL>();if (registries != null && !registries.isEmpty()) {//遍历registry配置信息for (RegistryConfig config : registries) {String address = config.getAddress();if (StringUtils.isBlank(address)) {address = NetUtils.LOCALHOST + ":" + MotanConstants.DEFAULT_INT_VALUE;}Map<String, String> map = new HashMap<String, String>();//将registry的各个属性,以键值对的形式存储在map中config.appendConfigParams(map);map.put(URLParamType.application.getName(), getApplication());map.put(URLParamType.path.getName(), RegistryService.class.getName());map.put(URLParamType.refreshTimestamp.getName(), String.valueOf(System.currentTimeMillis()));// 设置默认的registry protocol,parse完protocol后,需要去掉该参数if (!map.containsKey(URLParamType.protocol.getName())) {if (address.contains("://")) {map.put(URLParamType.protocol.getName(), address.substring(0, address.indexOf("://")));}map.put(URLParamType.protocol.getName(), MotanConstants.REGISTRY_PROTOCOL_LOCAL);}// address内部可能包含多个注册中心地址//将地址和参数构造成一个motan服务地址,类似于下面的格式:// zookeeper://127.0.0.1:2181/com.weibo.api.motan.registry.RegistryService?group=default_rpcList<URL> urls = UrlUtils.parseURLs(address, map);if (urls != null && !urls.isEmpty()) {for (URL url : urls) {url.removeParameter(URLParamType.protocol.getName());registryList.add(url);}}}}return registryList;}

3、生成协议和端口的键值对
一个service可以按多个protocol提供服务,不同protocol使用不同port 利用export来设置protocol和port,格式如下:
protocol1:port1,protocol2:port2
4、发布服务
Motan使用Netty做为底层的服务发布框架。
对于发布服务来说,doExport方法重点在下面的两句:

ConfigHandler configHandler = ExtensionLoader.getExtensionLoader(ConfigHandler.class).getExtension(MotanConstants.DEFAULT_VALUE);exporters.add(configHandler.export(interfaceClass, ref, urls));

ConfigHandler是一个很重要的对象,连接了配置和协议。
实现为SimpleConfigHandler,它主要提供如下几个方面的功能:
1、提供服务集群模块,可以增加过滤器
2、将service关联到具体的Protocol对象,后者是提供Netty服务的对象
3、提供注册和取消注册的功能
4、提供服务的注销功能
这个具体以后还会再提到。
configHandler的export方法将返回Export对象,该例子中使用的的”DefaultRpcExporter”实现;
Exporter是Motan中一个很重要的对象,它通过SPI配置创建EndpointFactory对象,并通过createServer方法暴露服务。
这部分的内容,之后还会详细看。

-EOF-

Motan服务的启动相关推荐

  1. windows7 php 无法启动服务,windows update服务无法启动怎么解决?

    解决方法:1.鼠标依次点击"开始"→"控制面板"→"系统和安全"→"管理工具"→"服务":2.找到W ...

  2. centeros7网络服务无法启动_Linux网络服务02——DHCP原理与配置

    Linux网络服务02--DHCP原理与配置 一.DHCP服务概述 1.DHCP(Dynamic Host Configuration Protocol)动态主机配置协议 DHCP是由Internet ...

  3. 解压版mysql安装服务失败怎么办_mysql-8.0.17解压版安装步骤及MySQL服务无法启动问题的解决办法...

    本人初学使用mysql数据库,由于喜欢使用解压版,于安装配置中遇到许多问题,部分未能在搜索引擎中找到答案,偶然找到解决办法,故于此留下一些随笔,方便自己也为网友提供一点点参考,如有错误的地方,请大家批 ...

  4. 执行cmd并获得结果_MySQL 服务无法启动 请键入 NET HELPMSG 3523 以获得更多的帮助...

    window10上安装了MySQL,用于开发web服务的测试.MySQL很久不使用,之前使用都是执行net start mysql启动,执行net stop mysql关闭.某天突然启动报错" ...

  5. CentOS下SVN服务的启动与关闭

    CentOS下SVN服务的启动与关闭 https://blog.csdn.net/testcs_dn/article/details/45394521 svnserver -d -r /var/svn ...

  6. “此iPhone不能使用,因为Apple Mobile Device服务没有启动”解决办法

    电脑正确连接iphone,打开itunes显示:此iPhone不能使用,因为Apple Mobile Device服务没有启动 原因是:Apple Mobile Device服务没有启动,打开wind ...

  7. 请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同...

    异常详细信息: System.Web.HttpException: 无法向会话状态服务器发出会话状态请求.请确保已启动 ASP.NET State service,并且客户端和服务器端口是相同的.如果 ...

  8. linux追踪tomcat报错信息,linux下tomcat服务的启动、关闭与错误跟踪

    linux下tomcat服务的启动.关闭与错误跟踪,远程连接到服务器以后,通常通过以下几种方式启动关闭tomcat服务: 1).启动tomcat服务 进入tomcat主目录下的bin目录,然后执行如下 ...

  9. MySQL5.7.11免安装版的安装和配置以及解决MYSQL服务无法启动问题

    首先在官网下载MySQL5.7.11免安装版,进行解压.打开文件夹,修改my-default.ini 拷贝一份,改名 my.ini,复制下面的配置信息到 my.ini 保存 <span styl ...

最新文章

  1. Loonframwork到SWT的移植测试(JAVA GAME TEST SOURCE)
  2. 【大咖论道】周志华,唐杰教授等专家,站在 2022,展望大模型的未来
  3. 并发模型之——基本概念
  4. JDeveloper中的Java反编译器
  5. 职场中什么样的员工最易发展?
  6. python制作饼状图
  7. C# WinFrom 对字符进行UTF-8编码
  8. OSGEARTH三维地形开源项目
  9. 使用 IntraWeb (22) - 基本控件之 TIWCalendar
  10. 使用git拉取远程仓库代码
  11. CentOS部署单机Presto
  12. go语言数组如何初始化问题? - 知乎
  13. 手把手教你做蓝牙小车(二)
  14. Akka 指南 之「消息传递可靠性」
  15. 联想装win7驱动遇到问题的解决
  16. 创新是企业发展的动力源
  17. 偏向锁、轻量锁、重量锁的理解
  18. 机器学习实验—K-MEANS聚类
  19. 游戏开发人员眼中的Unity 3D网页游戏測评报告
  20. tkinter动态表格 - 实时更新数据(TkinterTable)

热门文章

  1. android sqlite fts4,SQLite FTS3/FTS4与一些使用心得
  2. 程序员他们也可以很可爱幽默
  3. S270无线物联网数据监测4G RTU功能介绍
  4. 抽象语法树(AST)
  5. yeelink平台试玩
  6. 【论文阅读】CT-ICP: Real-time Elastic LiDAR Odometry with Loop Closure
  7. 运维自动化管理服务器 CheungSSH
  8. 蓝桥七届 冰雹数 JAVA
  9. 【中小型局域网络搭建】
  10. 深度学习——致命问题之Gradient Vanish