pulsar工具类

生产工厂类

import org.apache.pulsar.client.api.MessageId;
import org.apache.pulsar.client.api.Producer;
import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;


@Component
public class ProducerFactory {

    // 日志管理
    private static final Logger logger = LoggerFactory.getLogger(ProducerFactory.class);

    // Pulsar客户端对象
    @Autowired
    private PulsarClient client;

    // 消息生产者集合
    private ConcurrentHashMap<String, Producer<byte[]>> producerMap = new ConcurrentHashMap<>();

    /**
     * @param topic: 主题名称
     * @desc: 记录消息生产者
     * @creater: Rock.Zha
     * @createDate 2020/8/19 10:17
     */
    private Producer<byte[]> getTheProducer(String topic) {
        Producer<byte[]> producer = producerMap.get(topic);

        if (producer == null) {
            synchronized (topic.intern()) {
                producer = producerMap.get(topic);
                if (producer == null) {
                    try {
                        // topic 生产者消息写到哪个主题中
                        // producerName 生产者的名字,不唯一即可,如果不设置,会有默认值
                        // sendTimeout 超时时间
                        // 默认情况下,当队列已满时,所有对Send和SendAsync方法的调用都将失败,除非您将BlockIfQueueFull设置为true
                        producer = client.newProducer(Schema.BYTES)
                                .topic(topic)/*.producerName(Thread.currentThread().getName() + "_" + topic)*/
                                .batchingMaxPublishDelay(10, TimeUnit.MILLISECONDS)
                                .sendTimeout(10, TimeUnit.SECONDS)
                                .blockIfQueueFull(true).create();
                        producerMap.putIfAbsent(topic, producer);
                        return producer;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return producer;
    }


    /**
     * @param topic:   生产者消息写到哪个主题中
     * @param message: 生产者发送的内容
     * @desc: 向Pulsar发送Message
     * @creater: Rock.Zha
     * @createDate 2020/8/18 14:22
     */
    public void sendAsync(String topic, String message) {
        Producer<byte[]> producer = this.getTheProducer(topic);
        producer.sendAsync(message.getBytes()).thenAccept(msgId -> {
            logger.info("Message with ID %s successfully sent---发送成功", msgId);
        });
    }


    /**
     * 同步发送消息
     *
     * @param topic
     * @param message
     * @return
     */
    public String send(String topic, String message) {
        String info = null;
        try {
            Producer<byte[]> producer = this.getTheProducer(topic);
            MessageId messageId = producer.send(message.getBytes());
            if (messageId != null) {
                info = messageId.toString();
            }
            logger.info("pulsar无返值", info);
        } catch (Exception e) {
            logger.error("pulsar发送消息异常:", e);
        }
        return info;
    }

    /**
     * 同步发送消息
     *
     * @param topic
     * @param message
     * @return
     */
    public String sendDeliver(String topic, String message,Long delayTime) {
        String info = null;
        try {
            Producer<byte[]> producer = this.getTheProducer(topic);
            MessageId messageId =producer.newMessage()
                    .value(message.getBytes())
                    .deliverAfter(delayTime, TimeUnit.MINUTES) //单位可以自由选择
                    .send();
            if (messageId != null) {
                info = messageId.toString();
            }
            logger.info("pulsar无返值", info);
        } catch (Exception e) {
            logger.error("pulsar发送消息异常:", e);
        }
        return info;
    }

}

2.配置类

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;



@Scope
@Component
@Data
public class PulsarPathConfig {

    @Value("${pulsar.env.path}")
    private String pulsarPath;

}
import org.apache.pulsar.client.api.AuthenticationFactory;
import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.PulsarClientException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class PulsarClientConfiguration {

    @Value(value = "${pulsar.server.url}")
    private  String pulsarServerUrl;        // PurSar路径,从配置文件获取

    @Value(value = "${pulsar.env}")
    private String pulsarEnv;               // pulsar的连接环境、qa测试环境无需token、prd环境需要token

    @Value(value = "${pulsar.token}")       // pulsar的token加密方式
    private String token;

    static final String ENV_QA = "qa";
    static final String ENV_PRD = "prd";

    // @Bean注解注册bean,同时可以指定初始化和销毁方法
    @Bean
    @Scope("prototype")
    public PulsarClient pulsarClient() throws PulsarClientException {
        if (pulsarEnv.equals(ENV_QA)) {
            return PulsarClient.builder().serviceUrl(pulsarServerUrl).build();      // 测试环境无需token
        } else {
            return PulsarClient.builder().serviceUrl(pulsarServerUrl).authentication(AuthenticationFactory.token(token)).build();// 生产环境需要token
        }
    }
}

3.枚举类

**
 * 带参数的枚举常量(订阅者)
 */
public enum Subscription {
    DEMO("demo-subscription"),  // 测试

    NULL_SUBSCRIPTION("");
    private String name;

    Subscription(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
/**
 * 带参数的枚举常量(主题)
 */
public enum Topic {
DEMO("demo-topic", "demo-topic");


    private String code;

    private String name;

    Topic(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public static <T extends Topic> T getByCode(String code) {
        //通过反射取出Enum所有常量的属性值
        for (Topic topic : Topic.class.getEnumConstants()) {
            if (code.equals(topic.getCode())) {
                return (T) topic;
            }
        }
        return (T) Topic.NULL_TOPIC;
    }

    public String getName() {
        return name;
    }

    public String getCode() {
        return code;
    }
}

4.测试实例 

发送代码

String messageId = producerFactory.send(pulsarPathConfig.getPulsarPath() + Topic.XX.getName(), JSON.toJSONString("111"));
        if(EmptyUtils.isEmpty(messageId)){
            return false;
        }
        return true;

发送或处理业务逻辑失败后,重新发送延迟消息 

 try {
                //消费本条消息
                //发送延迟消息
                String messageId = producerFactory.sendDeliver(pulsarPathConfig.getPulsarPath() + Topic.XX.getName(),new String(message.getData(), "UTF-8"),5L );
                consumer.acknowledge(message);
            } catch (Exception e1) {
                e1.printStackTrace();
                log.error("延时业务异常:{}", e1.getMessage(), e1);
            }

 

消费代码

@Slf4j
@Component
public class CreateTaskPaInfoListener extends Thread {

    @Autowired
    private PulsarClient client;

    @Value("${pulsar.env.path}")
    private String pulsarPath;

   


    // 用于开启、停用监听
    private volatile boolean started = false;

    @PostConstruct
    public void doReceive() {
        this.started = true;
        this.start();
    }

    @PreDestroy
    public void shutdown() {
        this.started = false;
    }

    @Override
    public void run() {
        Consumer<byte[]> consumer = null;
        try {
            consumer = client.newConsumer(Schema.BYTES)
                    .topic(pulsarPath + Topic.XX.getName())
                    .subscriptionName(Subscription.XX.getName())
                    .subscriptionType(SubscriptionType.Shared)
                    .batchReceivePolicy(BatchReceivePolicy.builder()
                            .maxNumMessages(100)
                            .maxNumBytes(1024 * 1024)
                            .timeout(5000, TimeUnit.MILLISECONDS)
                            .build())
                    .subscribe();
        } catch (PulsarClientException e) {
            e.printStackTrace();
        }

        while (started) {
            Messages<byte[]> messages = null;
            try {
                messages = consumer.batchReceive();
            } catch (PulsarClientException e) {
                log.error("PulsarClientException接受消息异常:{}",e);
                // 消息批量接收失败,全部重置。
                consumer.negativeAcknowledge(messages);
                //return;
            }
            for (Message<byte[]> message : messages) {
                // 执行业务逻辑
                this.execute(consumer, message);
            }
        }
        try {
            consumer.close();
        } catch (PulsarClientException e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行业务逻辑
     *
     * @param consumer
     * @param message
     */
    private void execute(Consumer<byte[]> consumer, Message<byte[]> message) {
        try {
            String msg = new String(message.getData(), "UTF-8");
            Test conditionBean = JSONObject.parseObject(msg, Test.class);
            
           
            consumer.acknowledge(message);
        } catch (Exception e) {
            log.error("处理异常:{}", e.getMessage(), e);
            consumer.negativeAcknowledge(message);
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值