开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构:Messaging2】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/75/detail/15829
Messaging2(一)
内容介绍:
一、前言
二、消息机制解耦性
三、Jboss 启动
四、代码例子
五、Kafka 启动
一、前言
左侧为 server,右侧为 server,然后是 T GS,两者认证后两侧都存在 key。实际上只在此处认证,cloud 最终要访问的是底下的某一个应用 SS。既然 cloud 存在密钥,为什么不能将密钥提供给 SS,两者使用通信?为什么要通过 TGS将密钥分发给 SS,同时也提供给 cloud 一个密钥,cloud 与 SS之间为什么要使用新的密钥进行通信?
TGS 将密钥提供给 cloud后,与 cloud 通信使用该密钥,使用 TGS 的密钥就可以鉴别是否是 TGS 发送消息,如果是将TGS的密钥直接推给 SS,让SS使用与 cloud 进行通信,从 SS 要访问的角度讲,具备了冒充 TGS 的能力。如果 SS使用该密钥发送消息,那么 cloud 无法辨认是 TGS 还是 SS 发送。所以与不同的服务器要使用不同的密钥进行通信最安全。
二、消息机制解耦性
继续上节内容,消息机制有两方面:一方面为了做解耦,一方面是进行异步通信消除单一故障节点防止调用时间太长。那么解耦如何实现?
Cloud 与 server 进行通信,server 端有一个远程对象 a,有一个方法 m。客户端调用服务器功能找到 a 的引用,然后调用m 方法。此时两者之间为耦合的。必须是 a 类型的对象在提供该服务,如果 server 端想要改写逻辑,变成了b,需要调用 b 的 m,那么 cloud 端也需要做修改,代码不能使用。
第二种情况 server 端业务逻辑发生非常大变化,流程不再调a的m,而是调用a的n,那么cloud端也不能使用。所以clou d 端就与 server 端形成了一种解耦合。服务器端只要改变,客户端所有代码都得修改。那么就使用到消息机制解开解耦。两者不直接交互,中间有消息服务器 Message Server,两端就为消息的发送和接收者,两者对等。S 提供服务这端会告知 C 端调用服务时不能直接调用对象 a 的 m 方法或 a 的 n 方法。在消息中间件中有很多 Topic 和Queue,相当于邮局的邮箱,S 端定了一个邮箱名为Java:/Queue/A,此后 c 端只需要讲消息发送到 A 邮箱中,S 会不断的进行监听,一旦收到就会进行处理。
两者约定好一个机制,例如 C 端的 a.m 是在交水电费,可以直接发送文本{waterfee:120},clou 端就不需要再调用a.m(),而是直接发送一个文本。服务器端就会监听队列,寻找到该文本,然后进行处理。在进行处理时有一个onmessage 方法,就会触发,{waterfee:120}会作为参数写入 onmessage()中。拿到后再做处理进行解析等。过程中会看到发送消息端与接收消息端没有对对方的任何 API 进行绑定,即例如当把一封信寄入到邮局的A信箱时,只知道有人会进行处理,不关心到底是什么部门处理。
所以两端就实现了解耦,没有对 Server 端的 API 进行绑定,也不知道 Server 端是谁,只知道将消息发送过去即可。如果想知道交水费交完后是否成功,会在消息头中告知自己在邮局中的 B 信箱,S 端处理完后将信放到 B 中,C 端进行查看。S 端在解析 C 端发来的消息中,解析了消息头中的 JMSReplyTo 属性后可以知道处理完后结果放回 B 信箱中。
整个过程中,可以看出都是 MessageServer 客户端,两端都在 MessageServer 中的队列或者主题中发送消息,然后在里面阅读消息。至于到底由谁收取消息,C 端并不关心,只需要按照约定例如想要水费就发送消息到 A 信箱中。好处确实是进行解耦了。S 端的 onMessage()是调 a.m()来实现还是变动调 a.n()进行实现,这些对于客户端 C 端屏蔽,甚至若之后Server端换成另一个 server 进行处理也是对 C 端 屏蔽的,所以确实进行了解耦。但是也有负面情况,此处必须写{waterfee:120},如果写错成{waterfee},那么客户端代码编译、服务器端代码编译,消息服务器收到消息时都不会报错。及时即使写错了但是类型仍然是string类型,是一个文本,文本中内容出错不会报错。
例如写一个函数 a.m(),只能约定函数中传入 string 类型,传入的是字符串就是正确的,传入数字就会报错,但是字符串本身内容不能确定。所以类型就会变弱,原要求 a.m(),里面传入一个 int 整数类型、字符类型 char type 表示传入的是水费电费等。如果传入不对就会立刻报错,但是不能判断内容是否正确。无法在编译时校验,是它出现的一个问题。此外,编程模型比较负复杂,如果是解耦合,可以直接调用 a.m()方法,上节讲解的消息中间件的编程模型相比更复杂。要想调 a.m()如何调用呢?
即便是在 RMI 上 lookup,提供一个名字,然后中找到该对象就可以进行调用。但是在消息中间件中,第一步需要获得一个连接工厂,连接工厂在 JNDI 树上,类似数据库获取 datasource;第二步在上面获取一个连接;第三步在上面开启一个 session,session 有一个参数为 Queue,所以需要先到 JNDI 中找 Queue 或 Topic。然后再创建生产者或消费者,然后再创建一个 message,最后发送或者接收。所以编程模型变得复杂,两者之间对比优缺点明显,所以要看清它的缺点,利用它解耦的优势。
有了解耦特性后,图上情况不会再出现。不需要再进行两两之间交互,只需要通过一个消息中间件发消息,发完消息后消息中间件中需要有一个路由,需要将消息转发给谁,类似邮局需要知道如何将信送给收件方。这就是消息中间件的一个特点,从此可以看出,消息服务器本身是一个单点故障,如果崩溃,那么所有系统将不能互相通信。对比下,两种通信方式:同步通信和异步通信都存在优缺点,所以需要做取舍。
三、jboss 启动
Intellij IDEA 创建消息驱动 Bean-接收 JMS 消息
- https://www.cnblogs.com/yangyquin/p/5346104.html
Wildfly Messaging Configuration
-
https://docs.jboss.org/author/display/WFLY /Messaging+configuration
要使用 jboss,使用 compact 访问没有 JMS,Jboss 新的版本为 wildfly。所以在系统中安装后才能运行。
安装了新版本的 jboss 后使用 shell 脚本,此处写的为 linux 操作,若是 shell 脚本需要添加一个用户。
- $WILDFLY_HOME/bin/add-user.sh
HAOPENGdeiMac:bin haopengchen$ ./add-user.sh
what type of user do you wish to add?
a ) Management User ( mgmt-users.properties)
b) Application User (application-users.properties)(a):
- Add a mgmt-user //加入该用户
- For example: username: root, password: wildfly2020! //输入用户名和密码
-In $WILDFLY_HOME/standalone/configuration/mgmt.-users.properties //打开应用服务器的 properties 文件
如图就可以看到新加入的用户已经进入,密码经过加密,不是明文存储。
以上都完成后可以在应用服务器指定文件中新加入一个用户角色(Assign a role to the new user):
- In /standalone/configuration/appications-roles.properties
#guest=guest
root=mgmt-users
接着在配置文件中将要使用的 Queue 或 Topic 配置进去(Add JMS Server & Destination in standalone.xml):
以上是在应用服务器端需要完成的操作。即在应用服务器中配置如图:
相当于在邮局中建信箱。一旦做该操作必须要给用户赋权限。
之后 jboss 跑起来后会有一个控制台菜单 Standalone Server,可以看到 JNDI 树,然后就可以看到刚才绑定的代码。
例如 Java:jboss/exported+jms+topic+HelloWorldMDBTopic 才是完整的 topic 的名字,也是之后在 JNDI 中查找的队列名字。




