将kafka消息暂存至ThreadLocal中,seata事务完成后,再发送消息至kafka,如果seata事务失败,不发送消息。
一、 写一个注解拦截类
java
@Aspect
@Component
@Slf4j
public class BusinessLogTestAspect {
@Around("@annotation(com.cloud.util.businesslog.BusinessLogKevin)")
public Object toLog(ProceedingJoinPoint joinPoint) throws Throwable {
GlobalTransaction globalTransaction = GlobalTransactionContext.getCurrentOrCreate();
globalTransaction.begin();
Object result = null;
try{
result = joinPoint.proceed();
globalTransaction.commit();
// 发送kafka信息
List<String> messageList = KafkaThreadLocal.kafkaThreadLocal.get();
KafkaThreadLocal.kafkaThreadLocal.remove();
if(ObjectUtil.isNotEmpty(messageList)) {
// 发送Kafka消息
KafkaProducer<String, String> producer = null;
try {
producer = createKafkaProducer();
for(String message : messageList) {
producer.send(new ProducerRecord<>("ustomer", message));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(producer != null) {
producer.close();
}
}
}
} catch (Exception e) {
KafkaThreadLocal.kafkaThreadLocal.remove();
globalTransaction.rollback();
}
System.out.println("localStatus3 role:" + globalTransaction.getGlobalTransactionRole());
return result;
}
二、写一个创建kafka生产端的对象
java
private KafkaProducer<String, String> createKafkaProducer() {
Properties props = new Properties();
props.put(BOOTSTRAP_SERVERS_CONFIG, "17.30.194.2:9092,172.0.14.28:9093,17.30.19.9:9092");
// props.put(ENABLE_IDEMPOTENCE_CONFIG, "true");
// props.put(TRANSACTIONAL_ID_CONFIG, String.valueOf(System.currentTimeMillis()));
props.put(KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put("security.protocol", "SASL_PLAINTEXT");
props.put("sasl.mechanism", "SCRAM-SHA-256");
props.put("sasl.jaas.config", "org.apache.kafka.common.security.scram.ScramLoginModule required username='username' password='userpassword';");
return new KafkaProducer<>(props);
}
三、将消息暂存至ThreadLocal
java
public class KafkaThreadLocal {
public static final ThreadLocal<List<String>> kafkaThreadLocal = new ThreadLocal<>();
public static void send(String message) {
List<String> messageList = kafkaThreadLocal.get();
if(ObjectUtil.isEmpty(messageList)) {
messageList = Lists.newArrayList();
}
messageList.add(message);
kafkaThreadLocal.set(messageList);
}
}
另外一种办法比较简单:
io.seata.tm.api.transaction.TransactionHook 实现这个接口
io.seata.tm.api.transaction.TransactionHookManager 注册Hook