RabbitMQ操作代码封装
1、Message.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace XFC.RabbitMQ.Domain
{
/// <summary>
/// 消息实体
/// </summary>
public class Message
{
/// <summary>
/// 消息创建
/// </summary>
/// <param name="value">值</param>
/// <param name="headers">头信息</param>
/// <param name="contentType">MIME content type,缺省值为 text/plain</param>
public Message(string value, IDictionary<string, object> headers, string contentType)
{
Value = value;
Headers = headers;
ContentType = contentType;
} /// <summary>
/// 消息创建
/// </summary>
/// <param name="value">值</param>
/// <param name="headers">头信息</param>
public Message(string value, IDictionary<string, object> headers)
: this(value, headers, "text/plain")
{ } /// <summary>
/// 消息创建
/// </summary>
/// <param name="value">值</param>
/// <param name="contentType">MIME content type</param>
public Message(string value, string contentType)
: this(value, null, contentType)
{ } /// <summary>
/// 消息创建
/// </summary>
/// <param name="value">值</param>
public Message(string value)
: this(value, null, "text/plain")
{ } /// <summary>
/// 消息创建
/// </summary>
public Message()
: this("", null, "text/plain")
{ }
/// <summary>
/// 消息值
/// </summary>
public string Value { get; set; } /// <summary>
/// 消息头
/// </summary>
public IDictionary<string, object> Headers { get; set; } /// <summary>
/// MIME content type
/// </summary>
public string ContentType { get; set; }
}
}
2、RabbitMqPublisher.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RabbitMQ.Client;
using XFC.RabbitMQ.Domain; namespace XFC.RabbitMQ
{
public class RabbitMqPublisher
{
private readonly string _rabbitMqUri; /// <summary>
/// 构造函数
/// </summary>
/// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
public RabbitMqPublisher(string rabbitMqUri)
{
this._rabbitMqUri = rabbitMqUri;
} /// <summary>
/// 创建连接
/// </summary>
private IConnection CreateConnection()
{
var factory = new ConnectionFactory
{
Uri = new Uri(_rabbitMqUri)
}; return factory.CreateConnection();
} /// <summary>
/// 创建信道
/// </summary>
private IModel CreateChannel(IConnection con, string exchangeName, string exchangeType, string queueName, string routeKey)
{
var channel = con.CreateModel();
channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);
if (!string.IsNullOrEmpty(queueName))
{
channel.QueueDeclare(queueName, true, false, false, null); //创建一个消息队列,用来存储消息
channel.QueueBind(queueName, exchangeName, routeKey, null);
} channel.BasicQos(, , true); //在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息
return channel;
} /// <summary>
/// 发送ExchangeType类型为Direct的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="routeKey">消息路由key</param>
/// <param name="message">消息实体</param>
/// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
/// <returns></returns>
public bool PublishDirectMessage(string exchangeName, string routeKey, Message message, string queueName = "")
{
return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, new[] { message });
} /// <summary>
/// 批量发送ExchangeType类型为Direct的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="routeKey">消息路由key</param>
/// <param name="messages">消息实体</param>
/// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
/// <returns></returns>
public bool PublishDirectMessages(string exchangeName, string routeKey, IEnumerable<Message> messages, string queueName = "")
{
return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, messages);
} /// <summary>
/// 发送ExchangeType类型为Fanout的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="message">消息实体</param>
/// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
/// <returns></returns>
public bool PublishFanoutMessage(string exchangeName, Message message, string queueName = "")
{
return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", new[] { message });
} /// <summary>
/// 批量发送ExchangeType类型为Fanout的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="messages">消息实体</param>
/// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
/// <returns></returns>
public bool PublishFanoutMessages(string exchangeName, IEnumerable<Message> messages, string queueName = "")
{
return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", messages);
} private bool PublishMessage(string exchangeName, string exchangeType, string queueName, string routeKey, IEnumerable<Message> messages)
{
using (var con = CreateConnection())
{
using (var channel = CreateChannel(con, exchangeName, exchangeType, queueName, routeKey))
{
channel.ConfirmSelect();//启用消息发送确认机制 foreach (var message in messages)
{
var body = Encoding.UTF8.GetBytes(message.Value);
var properties = channel.CreateBasicProperties();
properties.Persistent = true; //使消息持久化
properties.Headers = message.Headers;
properties.ContentType = string.IsNullOrEmpty(message.ContentType) ? "text/plain" : message.ContentType;
channel.BasicPublish(exchangeName, routeKey, properties, body);
} return channel.WaitForConfirms();
}
}
}
}
}
3、RabbitMqQuery.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RabbitMQ.Client;
using XFC.RabbitMQ.Domain; namespace XFC.RabbitMQ
{
public class RabbitMqQuery
{
private readonly string _rabbitMqUri; /// <summary>
/// 构造函数
/// </summary>
/// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
public RabbitMqQuery(string rabbitMqUri)
{
this._rabbitMqUri = rabbitMqUri;
} /// <summary>
/// 创建连接
/// </summary>
private IConnection CreateConnection()
{
var factory = new ConnectionFactory
{
Uri = new Uri(_rabbitMqUri)
}; return factory.CreateConnection();
} /// <summary>
/// 拉取队列中的数据
/// </summary>
/// <param name="queueName">队列名</param>
/// <returns></returns>
public Message GetMessage(string queueName)
{
using (var con = this.CreateConnection())
{
var channel = con.CreateModel();
var rs = channel.BasicGet(queueName, true);
return ResultToMessage(rs);
}
} /// <summary>
/// 批量拉取队列中的数据
/// </summary>
/// <param name="queueName">队列名</param>
/// <param name="queryCount">拉取数据的条数,默认为1</param>
/// <returns></returns>
public Message[] GetMessages(string queueName, int queryCount = )
{
if (queryCount <= ){ queryCount = ; } var msgLst = new List<Message>();
using (var con = this.CreateConnection())
{
var channel = con.CreateModel();
for (int i = ; i < queryCount; i++)
{
var rs = channel.BasicGet(queueName, true);
if (rs != null)
{
msgLst.Add(ResultToMessage(rs));
}
else
{
break;
}
}
} return msgLst.ToArray();
} private Message ResultToMessage(BasicGetResult rs)
{
var msg = new Message();
if (rs != null)
{
var body = rs.Body;
msg.Value = Encoding.UTF8.GetString(body);
msg.ContentType = rs.BasicProperties.ContentType;
msg.Headers = rs.BasicProperties.Headers;
} return msg;
}
}
}
4、RabbitMqListener.cs
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using RabbitMQ.Client.Exceptions;
using XFC.Log;
using XFC.RabbitMQ.Domain; namespace XFC.RabbitMQ
{
/// <summary>
/// RabbitMq消息监听器
/// </summary>
public class RabbitMqListener : IDisposable
{
private ConnectionFactory _factory;
private IConnection _con;
private IModel _channel;
private EventingBasicConsumer _consumer;
private readonly string _rabbitMqUri;
private readonly string _queueName;
private Func<Message, bool> _messageHandler; /// <summary>
/// 释放标记
/// </summary>
private bool disposed; ~RabbitMqListener()
{
Dispose(false);
} /// <summary>
/// RabbitMQ消息监听器
/// </summary>
/// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
/// <param name="queueName">要监听的队列</param>
public RabbitMqListener(string rabbitMqUri, string queueName)
{
this._rabbitMqUri = rabbitMqUri;
this._queueName = queueName;
} /// <summary>
/// 创建连接
/// </summary>
private void CreateConnection()
{
_factory = new ConnectionFactory
{
Uri = new Uri(_rabbitMqUri),
RequestedHeartbeat = ,//与服务器协商使用的心跳超时间隔(以秒为单位)。
AutomaticRecoveryEnabled = true,//开启网络异常重连机制
NetworkRecoveryInterval = TimeSpan.FromSeconds(),//设置每10s重连一次网络
TopologyRecoveryEnabled = true //开启重连后恢复拓扑(交换,队列,绑定等等)。
}; _con = _factory.CreateConnection();
_con.ConnectionShutdown += (sender, e) => ReMessageListen();//掉线重新连接并监听队列消息
} /// <summary>
/// 创建信道
/// </summary>
private void CreateChannel()
{
_channel = _con.CreateModel();
_channel.BasicQos(, , true); //在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息
} private Message ResultToMessage(BasicDeliverEventArgs rs)
{
var msg = new Message();
if (rs != null)
{
var body = rs.Body;
msg.Value = Encoding.UTF8.GetString(body);
msg.ContentType = rs.BasicProperties.ContentType;
msg.Headers = rs.BasicProperties.Headers;
} return msg;
} /// <summary>
/// 监听队列消息
/// </summary>
/// <param name="messageHandler">消息处理器,当监测到队列消息时回调该处理器</param>
/// <returns>监听状态</returns>
public bool MessageListen(Func<Message, bool> messageHandler)
{
try
{
this.CreateConnection();
this.CreateChannel(); _consumer = new EventingBasicConsumer(_channel); //基于事件的消息推送方式
_consumer.Received += (sender, e) =>
{
var message = this.ResultToMessage(e);
if (messageHandler != null)
{
this._messageHandler = messageHandler;
try
{
var isOk = this._messageHandler(message);
if (isOk)
{
_channel.BasicAck(e.DeliveryTag, false);
}
}
catch (Exception ex)
{
LoggerManager.ErrorLog.Error("消息处理器执行异常:" + ex.Message, ex);
}
}
}; _channel.BasicConsume(_queueName, false, _consumer); //手动确认
return true;
}
catch (Exception ex)
{
LoggerManager.ErrorLog.Error("尝试监听队列消息出现错误:" + ex.Message, ex);
}
return false;
} private void ReMessageListen()
{
try
{
//清除连接及频道
CleanupResource(); var mres = new ManualResetEventSlim(false); //初始化状态为false
while (!mres.Wait()) //每3秒监测一次状态,直到状态为true
{
if (MessageListen(_messageHandler))
{
mres.Set(); //设置状态为true并跳出循环
}
}
}
catch (Exception ex)
{
LoggerManager.ErrorLog.Error("尝试连接RabbitMQ服务器出现错误:" + ex.Message, ex);
}
} /// <summary>
/// 清理资源
/// </summary>
private void CleanupResource()
{
if (_channel != null && _channel.IsOpen)
{
try
{
_channel.Close();
}
catch (Exception ex)
{
LoggerManager.ErrorLog.Error("尝试关闭RabbitMQ信道遇到错误", ex);
}
_channel = null;
} if (_con != null && _con.IsOpen)
{
try
{
_con.Close();
}
catch (Exception ex)
{
LoggerManager.ErrorLog.Error("尝试关闭RabbitMQ连接遇到错误", ex);
}
_con = null;
}
} protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
CleanupResource();
disposed = true;
} public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
5、RabbitMqDelayPublisher
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RabbitMQ.Client;
using XFC.Exceptions;
using XFC.RabbitMQ.Domain; namespace XFC.RabbitMQ
{
public class RabbitMqDelayPublisher
{
private readonly string _rabbitMqUri;
private readonly string _dlxExchangeName;
private readonly string _dlxQueueName;
private readonly string _dlxRouteKey; /// <summary>
/// 构造函数
/// </summary>
/// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
public RabbitMqDelayPublisher(string rabbitMqUri)
{
this._rabbitMqUri = rabbitMqUri;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
/// <param name="dlxExchangeName">死信队列交换机名称</param>
/// <param name="dlxQueueName">死信队列名称</param>
/// <param name="dlxRouteKey">死信队列消息路由key</param>
public RabbitMqDelayPublisher(string rabbitMqUri, string dlxExchangeName, string dlxQueueName, string dlxRouteKey)
: this(rabbitMqUri)
{
this._dlxExchangeName = dlxExchangeName;
this._dlxQueueName = dlxQueueName;
this._dlxRouteKey = dlxRouteKey;
}
/// <summary>
/// 创建连接
/// </summary>
private IConnection CreateConnection()
{
var factory = new ConnectionFactory
{
Uri = new Uri(_rabbitMqUri)
}; return factory.CreateConnection();
} /// <summary>
/// 创建信道
/// </summary>
private IModel CreateChannel(IConnection con, string exchangeName, string exchangeType, string queueName, string routeKey, int delayTime)
{
if (string.IsNullOrEmpty(queueName))
{
throw new XFCException("queueName不能为空");
} var channel = con.CreateModel(); var dlxExchangeName = string.IsNullOrEmpty(this._dlxExchangeName) ? string.Format("dlx_{0}", exchangeName) : this._dlxExchangeName;
var dlxQueueName = string.IsNullOrEmpty(this._dlxQueueName) ? string.Format("dlx_{0}", queueName) : this._dlxQueueName;
var dlxRouteKey = string.IsNullOrEmpty(this._dlxRouteKey) ? (string.IsNullOrEmpty(routeKey) ? Guid.NewGuid().ToString().Replace("-", "") : string.Format("dlx_{0}", routeKey)) : this._dlxRouteKey; channel.ExchangeDeclare(dlxExchangeName, ExchangeType.Direct, true, false, null);
channel.QueueDeclare(dlxQueueName, true, false, false, null);
channel.QueueBind(dlxQueueName, dlxExchangeName, dlxRouteKey, null); var args = new Dictionary<string, object>
{
{"x-message-ttl", delayTime},
{"x-dead-letter-exchange", dlxExchangeName},
{"x-dead-letter-routing-key", dlxRouteKey}
}; channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);
channel.QueueDeclare(queueName, true, false, false, args);
channel.QueueBind(queueName, exchangeName, routeKey, null); channel.BasicQos(, , true);
return channel;
} /// <summary>
/// 发送ExchangeType类型为Direct的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="routeKey">消息路由key</param>
/// <param name="expireTime">过期时间,单位为秒</param>
/// <param name="message">消息实体</param>
/// <param name="queueName">队列名(必填)</param>
/// <returns></returns>
public bool PublishDirectMessage(string exchangeName, string queueName, string routeKey, int expireTime, Message message)
{
return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, expireTime, new[] { message });
} /// <summary>
/// 批量发送ExchangeType类型为Direct的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="routeKey">消息路由key</param>
/// <param name="expireTime">过期时间,单位为秒</param>
/// <param name="messages">消息实体</param>
/// <param name="queueName">队列名(必填)</param>
/// <returns></returns>
public bool PublishDirectMessages(string exchangeName, string queueName, string routeKey, int expireTime, IEnumerable<Message> messages)
{
return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, expireTime, messages);
} /// <summary>
/// 发送ExchangeType类型为Fanout的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="expireTime">过期时间,单位为秒</param>
/// <param name="message">消息实体</param>
/// <param name="queueName">队列名(必填)</param>
/// <returns></returns>
public bool PublishFanoutMessage(string exchangeName, string queueName, int expireTime, Message message)
{
return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", expireTime, new[] { message });
} /// <summary>
/// 批量发送ExchangeType类型为Fanout的消息
/// </summary>
/// <param name="exchangeName">交换机名称</param>
/// <param name="expireTime">过期时间,单位为秒</param>
/// <param name="messages">消息实体</param>
/// <param name="queueName">队列名(必填)</param>
/// <returns></returns>
public bool PublishFanoutMessages(string exchangeName, string queueName, int expireTime, IEnumerable<Message> messages)
{
return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", expireTime, messages);
} private bool PublishMessage(string exchangeName, string exchangeType, string queueName, string routeKey, int expireTime, IEnumerable<Message> messages)
{
using (var con = CreateConnection())
{
using (var channel = CreateChannel(con, exchangeName, exchangeType, queueName, routeKey, expireTime * ))
{
channel.ConfirmSelect();//启用消息发送确认机制
foreach (var message in messages)
{
var body = Encoding.UTF8.GetBytes(message.Value);
var properties = channel.CreateBasicProperties();
properties.Persistent = true; //使消息持久化
properties.Headers = message.Headers;
properties.ContentType = string.IsNullOrEmpty(message.ContentType) ? "text/plain" : message.ContentType;
channel.BasicPublish(exchangeName, routeKey, properties, body);
}
var state = channel.WaitForConfirms();
return state;
}
}
}
}
}
6、Test
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RabbitMQ.Client;
using XFC.RabbitMQ.Domain; namespace XFC.RabbitMQ.Test
{
class Program
{
private const string RabbitHostUri = "amqp://guest:guest@localhost:5672/";
private const string ExchangeName = "xfc.mq.test";
private const string QueueName = "xfc.mq.test.queue";
private const string RouteKey = "xfc.mq.test.key"; static void Main(string[] args)
{
var publisher = new XFC.RabbitMQ.RabbitMqPublisher(RabbitHostUri);
var dic = new Dictionary<string, object>();
dic.Add("uniquekey", "s34sdf3423234523sdfdsgf");
dic.Add("callbackurl", "http://wwww.1234.com/callback"); var ms =new List<Message>();
for (int i = ; i < ; i++)
{
ms.Add(new Message("hello...", dic, "application/json"));
}
publisher.PublishDirectMessages(ExchangeName, RouteKey, ms, QueueName);
Console.WriteLine("is ok");
Console.ReadKey(); var mqQuery = new XFC.RabbitMQ.RabbitMqQuery(RabbitHostUri);
var ss = mqQuery.GetMessages(QueueName, );
foreach (var s in ss)
{
Console.WriteLine(s.Value);
Console.WriteLine(s.ContentType);
foreach (var header in s.Headers)
{
Console.WriteLine(header.Key + ":" + Encoding.UTF8.GetString((Byte[])header.Value));
} } Console.ReadKey(); using (var mqListener = new XFC.RabbitMQ.RabbitMqListener(RabbitHostUri, QueueName))
{
mqListener.MessageListen(msg =>
{
Console.WriteLine(msg.Value);
return true;
}); Console.WriteLine("按任意键退出程序...");
Console.ReadKey();
}
}
}
}
RabbitMQ操作代码封装的更多相关文章
- 基础拾遗----RabbitMQ(含封装类库源码)
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
- c#读写共享内存操作函数封装
原文 c#读写共享内存操作函数封装 c#共享内存操作相对c++共享内存操作来说原理是一样,但是c#会显得有点复杂. 现把昨天封装的读写共享内存封装的函数记录下来,一方面希望给需要这块的有点帮助,另一方 ...
- C# .NET更智能的数据库操作的封装
前述: 对数据库操作的封装,相信网络上已经有一大堆,ORM框架,或者是.NET本身的EF,都很好的支持数据库操作.这篇文章是分享自己所思考的,对数据库操作的简单封装.我对于这篇文章,认为被浏览者所关注 ...
- 手把手封装数据层之DataUtil数据库操作的封装
上一篇我们写完了数据库连接的封装 没有看的请移步上一篇关于数据库连接的内容 这次我们讲数据库操作的封装.数据库的操作就是增删改查:心再大一点就可以直接分为查询和其他. 因为查询是有返回对象的,而其他都 ...
- Asp.Net Core 2.0 项目实战(4)ADO.NET操作数据库封装、 EF Core操作及实例
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- 将自己写的HDL代码封装成带AXI总线的IP
将自己写的HDL代码封装成带AXI总线的IP 1.Tools->create and package IP 2.create AXI4总线的IP 3.新建block design 4.点击右键, ...
- MVP+Dagger2+Rxjava+Retrofit+GreenDao 开发的小应用,包括新闻、图片、视频3个大模块,代码封装良好
练习MVP架构开发的App,算是对自己学过的知识做一个总结,做了有一段时间,界面还算挺多的.代码量还是有的,里面做了大量封装,总体代码整理得非常干净,这个我已经尽力整理了. 不管是文件(java.xm ...
- XML序列化 判断是否是手机 字符操作普通帮助类 验证数据帮助类 IO帮助类 c# Lambda操作类封装 C# -- 使用反射(Reflect)获取dll文件中的类型并调用方法 C# -- 文件的压缩与解压(GZipStream)
XML序列化 #region 序列化 /// <summary> /// XML序列化 /// </summary> /// <param name="ob ...
- 数据操作的封装--sqlhelper
为了提高软件的灵活性和可维护性,软件的代码须要科学的管理.我们引入了架构这个词.设计模式提醒我们,软件中反复性的代码须要封装起来. 近期在做收费系统时.须要和数据库进行频繁的联系.既然是反复的使用,就 ...
随机推荐
- 用openresty(Lua)写一个获取YouTube直播状态的接口
文章原发布于:https://www.chenxublog.com/2019/08/29/openresty-get-youtube-live-api.html 之前在QQ机器人上面加了个虚拟主播开播 ...
- C# 分布式自增ID算法snowflake(雪花算法)
概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的.有些时候我们希望能使用一种简 ...
- PC端页面适应不同的分辨率的方法
原文链接:https://www.jianshu.com/p/4850a7b22228 一.根据不同的分辨率,加载不同的CSS样式文件 这个方法的思路是,分别针对800.1280.1440.1600. ...
- webpack4 plugins 篇
demo 代码点此,篇幅有限,仅介绍几个常用的. start 什么是 plugins ? While loaders are used to transform certain types of mo ...
- 电信NBIOT 2 - 数据上行(中间件获取电信消息通知)
电信NBIOT 1 - 数据上行(中国电信开发者平台对接流程) 电信NBIOT 2 - 数据上行(中间件获取电信消息通知) 电信NBIOT 3 - 数据下行 电信NBIOT 4 - NB73模块上行测 ...
- 白话SCRUM 之三:sprint backlog
Sprint Backlog就是任务列表,如果映射到传统的项目管理理论中就是WBS(work breakdown structure),而且是典型的采用面向交付物的任务分解方法得到的WBS. 比如有一 ...
- [PHP] 项目实践中使用的IOC容器思想
1.容器的意思就是一个全局变量,里面存了很多对象,如果要用到某个对象就从里面取,前提就是要先把对象放进去2.控制反转就是把自己的控制权交给别人3.这两个结合就是,把自己的控制权交给别人并且创建的对象放 ...
- Linux内核编程、调试技巧小集【转】
转自:https://www.cnblogs.com/arnoldlu/p/7152488.html 1. 内核中通过lookup_symbol_name获取函数名称 内核中很多结构体成员是函数,有时 ...
- Springboot jackSon -序列化-详解
在项目中有事需要对值为NULL的对象中Field不做序列化输入配置方式如下: [配置类型]: 源码包中的枚举类: public static enum Include { ALWAYS, NON_NU ...
- c# 第10节 表达式
本节内容: 1:表达式是什么 2:表达式实例 1:表达式是什么 2:表达式实例 3:运算符分类