RocketMQ源码系列(三)RocketMQ消息发送,生产者producer源码篇(上)生产者启动流程

1、消息对象

消息对象message中封装了主题、消息标记、消息属性(tags、keys等)、消息内容等信息。

所在包org.apache.rocketmq.common.message

public class Message implements Serializable {
    
    
    private static final long serialVersionUID = 8445773977080406428L;

    private String topic;//主题
    private int flag;//消息标记
    //消息属性,主要存储如tags、keys等信息
    private Map<String, String> properties;
    private byte[] body;//消息内容
    private String transactionId;

    public Message() {
    
    
    }

    public Message(String topic, byte[] body) {
    
    
        this(topic, "", "", 0, body, true);
    }

    public Message(String topic, String tags, String keys, int flag, byte[] body, boolean waitStoreMsgOK) {
    
    
        this.topic = topic;
        this.flag = flag;
        this.body = body;
		//设置key
        if (tags != null && tags.length() > 0)
            this.setTags(tags);
		//设置tag
        if (keys != null && keys.length() > 0)
            this.setKeys(keys);
        //消息发送时,是否等消息存储完成后再返回
        this.setWaitStoreMsgOK(waitStoreMsgOK);
    }

2、生产者启动流程

2.1、默认生产者DefaultMQProducer

所在包org.apache.rocketmq.client.producer

DefaultMQProducer主要属性

public class DefaultMQProducer extends ClientConfig implements MQProducer {
    
    

    /**
     *该内中方法实现类
     */
    protected final transient DefaultMQProducerImpl defaultMQProducerImpl;
    private final InternalLogger log = ClientLogger.getLog();

    /**
     * 生产者所在组,消息服务器在回查事务状态时,
     * 会随机选择该组中任何一个生产者发起事务回查请求
     */
    private String producerGroup;

    /**
     * 默认TopicKey
     */
    private String createTopicKey = TopicValidator.AUTO_CREATE_TOPIC_KEY_TOPIC;

    /**
     * 默认每个topic的队列数量为4
     */
    private volatile int defaultTopicQueueNums = 4;

    /**
     * 发送消息的默认超时时间是3秒
     */
    private int sendMsgTimeout = 3000;

    /**
     * 消息大小超过4kb,则启用压缩
     */
    private int compressMsgBodyOverHowmuch = 1024 * 4;

    /**
     * 同步发送消息失败时默认重试2次,同一消息最多尝试发送3次
     */
    private int retryTimesWhenSendFailed = 2;

    /**
     * 异步发送消息失败时默认重试2次,同一消息最多尝试发送3次
     */
    private int retryTimesWhenSendAsyncFailed = 2;

    /**
     * 消息重试时选择另外一个broker时,是否不等待存储结果就返回,
     * 默认为false表示要等待结果
     */
    private boolean retryAnotherBrokerWhenNotStoreOK = false;

    /**
     * 允许发送的最大消息,默认为4M
     */
    private int maxMessageSize = 1024 * 1024 * 4; // 4M

    /**
     * 异步传输数据接口
     */
    private TraceDispatcher traceDispatcher = null;

创建主题的方法

	public void createTopic(
                            String key, /* 没有实际作用 */
                            String newTopic, /* 主题 */
                            int queueNum, /* 队列数量 */
                            int topicSysFlag/* 主题系统标签,默认为0 */
                            ) throws MQClientException {
    
    
        this.defaultMQProducerImpl.createTopic(key, withNamespace(newTopic), queueNum, topicSysFlag);
    }

2.2、生产者启动流程

所在包:org.apache.rocketmq.client.impl.producer
类:DefaultMQProducerImpl类
方法:start()

	public void start() throws MQClientException {
    
    
        this.start(true);
    }

2.2.1 生产者组检查

检查生产者组是否符合要求,包括不能为空,长度小于255,并且不能包括非法字符。并改变生产者的instanceName为进程ID

this.checkConfig();
    private void checkConfig() throws MQClientException {
    
    
        Validators.checkGroup(this.defaultMQProducer.getProducerGroup());

        if (null == this.defaultMQProducer.getProducerGroup()) {
    
    
            throw new MQClientException("producerGroup is null", null);
        }

        if (this.defaultMQProducer.getProducerGroup().equals(MixAll.DEFAULT_PRODUCER_GROUP)) {
    
    
            throw new MQClientException("producerGroup can not equal " + MixAll.DEFAULT_PRODUCER_GROUP + ", please specify another one.",
                null);
        }
    }

2.2.2 改变生产者的instanceName为进程ID

		if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) {
    
    
            this.defaultMQProducer.changeInstanceNameToPID();
        }

2.2.3 创建MQClientInstance实例

创建MQClientInstance实例,

this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQProducer, rpcHook);

首先创建clientId,尝试从factoryTable获取clientId对应的MQClientInstance,如果获取不到则新建MQClientInstance,添加新的MQClientInstance,并返回旧的MQClientInstance,如果旧的MQClientInstance不为空,返回旧的MQClientInstance,否则返回新创建的对象。

    public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientConfig, RPCHook rpcHook) {
    
    
        //创建clientId
        String clientId = clientConfig.buildMQClientId();
        //尝试从factoryTable获取clientId对应的MQClientInstance
        MQClientInstance instance = this.factoryTable.get(clientId);
        if (null == instance) {
    
    
            //如果获取不到则新建MQClientInstance
            instance =
                new MQClientInstance(clientConfig.cloneClientConfig(),
                    this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);
            //添加新的MQClientInstance,并返回旧的MQClientInstance
            MQClientInstance prev = this.factoryTable.putIfAbsent(clientId, instance);
            if (prev != null) {
    
    
                //如果旧的MQClientInstance不为空,则赋值给新的变量
                instance = prev;
                log.warn("Returned Previous MQClientInstance for clientId:[{}]", clientId);
            } else {
    
    
                log.info("Created new MQClientInstance for clientId:[{}]", clientId);
            }
        }
        //返回新建的MQClientInstance或者旧值
        return instance;
    }

clientId为本机IP+InstanceName+unitName(可选)

    public String buildMQClientId() {
    
    
        StringBuilder sb = new StringBuilder();
        //获取本机IP
        sb.append(this.getClientIP());

        sb.append("@");
        sb.append(this.getInstanceName());
        if (!UtilAll.isBlank(this.unitName)) {
    
    
            sb.append("@");
            sb.append(this.unitName);
        }

        return sb.toString();
    }

2.2.4 向MQClientInstance中注册producer

向MQClientInstance中注册producer,将当前生产者加入到MQClientInstance中进行管理,方便后续调用网络请求,进行心跳检测等

                boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this);
                if (!registerOK) {
    
    
                    this.serviceState = ServiceState.CREATE_JUST;
                    throw new MQClientException("The producer group[" + this.defaultMQProducer.getProducerGroup()
                        + "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL),
                        null);
                }

2.2.5 启动MQClientInstance实例

                /*
                 * 添加topic信息对象
                 */
                this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo());
                // 启动MQClientInstance实例。
                if (startFactory) {
    
    
                    mQClientFactory.start();
                }

                log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(),
                    this.defaultMQProducer.isSendMessageWithVIPChannel());
                this.serviceState = ServiceState.RUNNING;
                break;

猜你喜欢

转载自blog.csdn.net/weixin_43073775/article/details/109457923