温故而知新-Steel Mdp 笔记(原理篇)

同样的客观存在的事物,在不同的阶段我们对它们的认知程度是不一样的。因为认知主体在变化,外界环境在变化、客观事物本身也可能在变化。温故而知新,近日再次翻出之前看过的steel-mdp源码,再次仔细拜读,又有不一样的收获。在感叹写这个框架的人如此诣熟Spring框架的同时,也随手记录下心得及这个框架的运行原理。

先借用一下Martin大师的两张MDP 客户端和服务端的图来异常一下STEEL MDP的组件间的关系。

客户端:


服务端:

下面来详细分析一下服务端和客户端在服务启动和消息处理两个阶段的运行机制原理。
服务端
 
容器启动阶段
类图:


时序图:

 
概述 :服务端容器启动时,会遍历所有标有@MdpService的服务bean,然后每个服务实例创建一个MdpInvokerServiceExporter,然后对于声明相同队列的服务实例则封装到MdpServiceBusExporter内,之后再创建消息监听容器MdpSimpleMessageListenerContainer,并指定刚才创建的MdpServiceBusExporter作为监听器。每个队列分别创建自己的MdpSimpleMessageListenerContainer。最后依次启动每个MdpSimpleMessageListenerContainer。容器启动过程中,会初始化一些基本资源,如:创建Connection,Session,MessageConsumer。每个队列都会创建一定数量的Consumer,这个根据客户端配置,默认是5个。至此,服务端服务注册完毕。这样当有Consumer发送消息到指定队列时,队列对应监听容器则会收到消息,并会派发给指定的listener(即MdpServiceBusExporter)去处理,通常是onMessage()方法。

 
处理消息 阶段:
时序图:

概述:客户端把消息发送到指定队列后,监听该队列的容器就会拿到消息,然后转发给它的监听者(MdpInvokerBusExplorer)处理。
BusExplorer接收到请求,会先根据beanName寻找ServiceExporter如果找不到,再根据interfaceName寻找ServiceExporter。找到相应实例后,把请求委托给ServiceExplorer处理。
ServiceExplorer接收到请求 后,首先把请求Message反序列化为RemoteInvocation,然后调用目标服务方法,把目标服务的处理结果处理为RemoteInvocationResult,然后把RemoteInvocationResult序列化为应答Message,发送到请求Message中指定的临时队列里。
客户端:

容器启动阶段
类图:
时序图:
概述 :Spring容器在初始化时,会遍历所有标有@MdpWired的服务bean,然后创建一个MdpInvokerProxyFactoryBean,并以此作为advise生成服务代理类,最后将服务代理类注入给目标bean.

 
方法调用阶段
时序图:
概述:由于MdpInvokerProxyFactoryBean已经在容器启动阶段作为一个advise被封装到代理实现类并注入到调用端目标bean,所以请求发起时,首先被Spring容器的advise(即MdpInvokerProxyFactoryBean)拦截到,并在MdpRequestor内将请求信息序列化为请求Message,发送到指定队列中。然后在同步块内锁住应答块(ResponseTub),此时主线程并处于Stepping状态,等待服务端返回。
服务端接收到消息,处理完毕并将应答消息放入到队列后,客户端监听该队列的子线程(Consumer)会立刻取到该消息。然后在同步块内锁住应答块(ResponseTub)将应答消息赋给响应块。同时唤醒主线程。
主线程被唤醒后,拿到刚才由监听子线程从临时队列中取到的应答Message,并将其反序列化为RemoteInvocationResult,并从其中解析出真正的调用结果,反馈给调用端。


主要的组件分析

1.MdpBeanPostProcessor:一个组件能承载多少功能,很大程度上取决于这个组件实现了多少接口和继承了多少组件。这个组件实现了5个接口。我们来分别看一下。
     实现了ApplicationContextAware,让它拥有感知Spring上下文的能力,在Spring容器启动时,容器会把上下文注入给此组件,供组件获取容器内管理的bean。
     实现了SmartLifecycle,让其拥有生命周期管理功能,并将这委托给Spring。在Spring容器启动的最后一步,会加载所有实现了LifeCylcle的组件,并启动它们。当Spring容器关闭时,会销毁相关资源。
     实现了BeanPostProcessor,让其有bean后置处理能力。每个Spring管理的bean在其被容器加载后,都被经过此组件,此组件过滤到自己识别的bean然后进行处理。如在steel mdp中,spring容器启动时,客户端对代理实现的注入、服务端把服务实例的注册都是在此组件内完成。
2.MdpInvokerProxyFactoryBean:此组件实现了BeanClassLoaderAware,可以在容器启动时向此组件注入classloader,另外它还实现了FactoryBean,MethodInterceptor,在客户端容器启动时,将服务端接口信息封装到FactoryBean,由于此组件实现interceptor而具有方法拦截功能。具体点说,客户端容器启动时就创建了一个factorybean,然后将其注入给客户端,然后在客户端真正发起方法调用时,由factorybean的invoke方法拦截到,然后包装请求参数,向队列内发送请求消息。
3.  MdpServiceBusExporter:此组件承载两大功能:1.在容器启动时,负责把同一队列的服务实例(Consumer)注册到对应的BusExporer上,一个BusExplorer对应一个消息队列。 2.处理消息时,负责寻找MdpInvokerServiceExporter,然后把请求派发给其处理。
4. MdpInvokerServiceExporter:此组件是真正消费消息的地方,在此组件内,首先把Message反序列化为RemoteInvocation,然后再委托给Spring的组件去处理,由于它继承了RemoteInvocationBasedExporter,因此它具有极强的方法反射能力。当拿到处理结果后,再把处理结果包装为RemoteInvocationResult,并发发送到客户端指定的临时队列里。
5. MdpRequestor:该组件是客户端容器启动时被实例化,并注册给FactoryBean。当客户端发送调用请求时,请求到达FactoryBean时,请求完全委托给requestor处理,返回给Factorybean的是RemoteInvocationResult。由于requestor创建时被注入了conntctionFactory,所以它内部具备将请求消息包装并发送到指定列队的能力。如:利用conntctionFactory创建Connection,Session等。它将请求信息序列化为RemoteInvocation,并创建MessageProducer将请求信息发送到队列,然后另起一个线程创建临时队列,并创建MessageConsumer来监听来自于临时队列上的应答结果。
服务端线程详解
 

 
客户端线程详解
 



Spring启动时是如何启动SimpleMessageListenerContainer的?



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值