例如 用戶注冊之后需要計(jì)算用戶的邀請關(guān)系,遞歸操作屿衅。如果注冊的時候包含多步驗(yàn)證娱颊,生成基本初始化數(shù)據(jù),這時候我們通過mq發(fā)送消息來處理這個邀請關(guān)系箱硕,會出現(xiàn)一個問題,就是用戶還沒注冊數(shù)據(jù)還沒入庫栓拜,邀請關(guān)系就開始執(zhí)行,但是查不到數(shù)據(jù)挑势,導(dǎo)致出錯啦鸣。
@TransactionalEventListener 可以實(shí)現(xiàn)事務(wù)的監(jiān)聽,可以在提交之后再進(jìn)行操作诫给。
——————————————
1.實(shí)體類
@Data
public class Customer {
private Integer id;
private String name;
}
2.監(jiān)聽的對象
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* fileName:RegCustomerEvent
* description:
* author: LJV
* createTime:2022/8/19 14:41
* version:1.0.0
*/
@Getter
public class RegCustomerEvent extends ApplicationEvent {
private Customer customer;
/***
* @description 構(gòu)造函數(shù)火脉,用于設(shè)置消息體屬性內(nèi)容
* @author 朱孝恒(javazhuxiaoheng @ 163.com)
* @date 2022-03-17
* @param customer 推送對象
*/
public RegCustomerEvent(Customer customer) {
super(customer);
this.customer = customer;
}
}
3.Spring事務(wù)事件發(fā)送, 用于調(diào)用ApplicationEventPublisher發(fā)布事件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
/**
* fileName:TranscationEventPublisher
* description:Spring事務(wù)事件發(fā)送, 用于調(diào)用ApplicationEventPublisher發(fā)布事件
* author: LJV
* createTime:2022/8/19 14:58
* version:1.0.0
*/
@Service
public class TranscationEventPublisher {
/**
* Spring事件發(fā)布器對象
*/
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/***
* @description 發(fā)布數(shù)據(jù)生成事件
* @author
* @date 2022-03-17
* @param customer
*/
public void publishCustomerEvent(Customer customer) {
applicationEventPublisher.publishEvent(new RegCustomerEvent(customer));
}
}
4.消息事件監(jiān)聽器
package com.ljv.chat.event_;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* fileName:TranscationMessageListener
* description: 消息事件監(jiān)聽器
* author: LJV
* createTime:2022/8/19 15:04
* version:1.0.0
*/
@Component
@Slf4j
public class TranscationMessageListener {
/***
* @description 本地事務(wù)監(jiān)聽事件瘩蚪,事務(wù)完成后妓柜,發(fā)布一條推送訂單給司機(jī)的MQTT消息
* @author 朱孝恒(javazhuxiaoheng @ 163.com)
* @date 2022-03-17
* @param regCustomerEvent 消息事件主題
*/
@Async //如果使用該異步注解勋又,則需要 @EnableAsync在主類
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
public void pushCustomer(RegCustomerEvent regCustomerEvent) {
log.info("freightSendEvent: {}", regCustomerEvent);
//業(yè)務(wù)邏輯
System.out.println("---事件開始執(zhí)行---");
}
}
5.工具類
package com.ljv.chat.event_;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* spring工具類 方便在非spring管理環(huán)境中獲取bean
*
* @author hupengnan
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
/** Spring應(yīng)用上下文環(huán)境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
SpringUtils.beanFactory = beanFactory;
}
/**
* 獲取對象
*
* @param name
* @return Object 一個以所給名字注冊的bean的實(shí)例
* @throws BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
/**
* 獲取類型為requiredType的對象
*
* @param clz
* @return
* @throws BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException
{
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一個與所給名稱匹配的bean定義赐写,則返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name)
{
return beanFactory.containsBean(name);
}
/**
* 判斷以給定名字注冊的bean定義是一個singleton還是一個prototype挺邀。 如果與給定名字相應(yīng)的bean定義沒有被找到,將會拋出一個異常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注冊對象的類型
* @throws NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getType(name);
}
/**
* 如果給定的bean名字在bean定義中有別名泣矛,則返回這些別名
*
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getAliases(name);
}
}
6.服務(wù)層接口
package com.ljv.chat.event_.service;
/**
* fileName:Customer
* description:
* author: LJV
* createTime:2022/8/19 16:36
* version:1.0.0
*/
public interface CustomerService {
void getCustomer();
}
7.服務(wù)層實(shí)現(xiàn)類
package com.ljv.chat.event_.service;
import com.ljv.chat.event_.Customer;
import com.ljv.chat.event_.SpringUtils;
import com.ljv.chat.event_.TranscationEventPublisher;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.TimeUnit;
/**
* fileName:CustomerServiceImpl
* description:
* author: LJV
* createTime:2022/8/19 16:38
* version:1.0.0
*/
@Service
@Slf4j
public class CustomerServiceImpl implements CustomerService {
@Override
@Transactional
public void getCustomer() {
log.info("---業(yè)務(wù)開始執(zhí)行---");
Customer customer = new Customer();
customer.setId(1);
customer.setName("qweqwe");
log.info("aaa");
SpringUtils.getBean(TranscationEventPublisher.class).publishCustomerEvent(customer);
log.info("ccc");
// Thread.sleep(1000);
try {
TimeUnit.SECONDS.sleep(10);//秒
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("---業(yè)務(wù)執(zhí)行結(jié)束---");
}
}
8.控制層 進(jìn)行測試
package com.ljv.chat.event_;
import com.ljv.chat.event_.service.CustomerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* fileName:Test
* description:
* author: LJV
* createTime:2022/8/19 15:09
* version:1.0.0
*/
@RestController
@RequestMapping("customer")
@Slf4j
public class TestController {
@Autowired
private CustomerService customerService;
@GetMapping("getCustomer")
public void getCustomer() throws InterruptedException {
customerService.getCustomer();
}
}