最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解基于Spring Data的領(lǐng)域事件發(fā)布

 更新時(shí)間:2020年04月02日 09:22:04   作者:barry的異想世界  
這篇文章主要介紹了詳解基于Spring Data的領(lǐng)域事件發(fā)布,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

領(lǐng)域事件發(fā)布是一個(gè)領(lǐng)域?qū)ο鬄榱俗屍渌鼘?duì)象知道自己已經(jīng)處理完成某個(gè)操作時(shí)發(fā)出的一個(gè)通知,事件發(fā)布力求從代碼層面讓自身對(duì)象與外部對(duì)象解耦,并減少技術(shù)代碼入侵。

一、 手動(dòng)發(fā)布事件

// 實(shí)體定義
@Entity
public class Department implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer departmentId;

  @Enumerated(EnumType.STRING)
  private State state;
}

// 事件定義
public class DepartmentEvent {
  private Department department;
  private State state;
  public DepartmentEvent(Department department) {
    this.department = department;
    state = department.getState();
  }
}

// 領(lǐng)域服務(wù)
@Service
public class ApplicationService {

  @Autowired
  private ApplicationEventPublisher applicationEventPublisher;

  @Autowired
  private DepartmentRepository departmentRepository;

  @Transactional(rollbackFor = Exception.class)
  public void departmentAdd(Department department) {
    departmentRepository.save(department);
    // 事件發(fā)布
    applicationEventPublisher.publishEvent(new DepartmentEvent(department));
  }
}

使用applicationEventPublisher.publishEvent在領(lǐng)域服務(wù)處理完成后發(fā)布領(lǐng)域事件,此方法需要在業(yè)務(wù)代碼中顯式發(fā)布事件,并在領(lǐng)域服務(wù)里引入ApplicationEventPublisher類(lèi),但對(duì)領(lǐng)域服務(wù)本身有一定的入侵性,但靈活性較高。

二、 自動(dòng)發(fā)布事件

// 實(shí)體定義
@Entity
public class SaleOrder implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer orderId;
  
  @Enumerated(EnumType.STRING)
  private State state;

  // 返回類(lèi)型定義
  @DomainEvents
  public List<Object> domainEvents(){
    return Stream.of(new SaleOrderEvent(this)).collect(Collectors.toList());
  }

  // 事件發(fā)布后callback
  @AfterDomainEventPublication
  void callback() {
    System.err.println("ok");
  }
}

// 事件定義
public class SaleOrderEvent {
  private SaleOrder saleOrder;
  private State state;
  public SaleOrderEvent(SaleOrder saleOrder) {
    this.saleOrder = saleOrder;
    state = saleOrder.getState();
  }
}

// 領(lǐng)域服務(wù)
@Service
public class ApplicationService {
  @Autowired
  private OrderRepository orderRepository;
  
  @Transactional(rollbackFor = Exception.class)
  public void saleOrderAdd(SaleOrder saleOrder) {
    orderRepository.save(saleOrder);
  }
}

使用@DomainEvents定義事件返回的類(lèi)型,必須是一個(gè)集合,使用@AfterDomainEventPublication定義事件發(fā)布后的回調(diào)。

此方法實(shí)事件類(lèi)型定義在實(shí)體中,與領(lǐng)域服務(wù)完全解耦,沒(méi)有入侵。系統(tǒng)會(huì)在orderRepository.save(saleOrder)后自動(dòng)調(diào)用事件發(fā)布,另delete方法不會(huì)調(diào)用事件發(fā)布。

三、 事件監(jiān)聽(tīng)

@Component
public class ApplicationEventProcessor {

  @EventListener(condition = "#departmentEvent.getState().toString() == 'SUCCEED'")
  public void departmentCreated(DepartmentEvent departmentEvent) {
    System.err.println("dept-event1:" + departmentEvent);
  }

  @Async
  @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, condition = "#saleOrderEvent.getState().toString() == 'SUCCEED'")
  public void saleOrderCreated(SaleOrderEvent saleOrderEvent) {
    System.err.println("sale-event succeed1:" + saleOrderEvent);
  }

  @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT, condition = "#saleOrderEvent.getState().toString() == 'SUCCEED'")
  public void saleOrderCreatedBefore(SaleOrderEvent saleOrderEvent) {
    System.err.println("sale-event succeed2:" + saleOrderEvent);
  }

  @Async
  @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
  public void saleOrderCreatedFailed(SaleOrderEvent saleOrderEvent) {
    System.out.println("sale-event failed:" + saleOrderEvent);
  }
}

1. 使用@EventListener監(jiān)聽(tīng)事件

@EventListener沒(méi)有事務(wù)支持,只要事件發(fā)出就可監(jiān)控到

@Transactional(rollbackFor = Exception.class)
public void departmentAdd(Department department) {
  departmentRepository.save(department);
  applicationEventPublisher.publishEvent(new DepartmentEvent(department));
  throw new RuntimeException("failed");
}

上述情況會(huì)造成事務(wù)失敗回滾,但事件監(jiān)控端已經(jīng)執(zhí)行,可能導(dǎo)致數(shù)據(jù)不一致的情況發(fā)生

2. 使用@TransactionalEventListener監(jiān)聽(tīng)事件

  • TransactionPhase.BEFORE_COMMIT 事務(wù)提交前
  • TransactionPhase.AFTER_COMMIT 事務(wù)提交后
  • TransactionPhase.AFTER_ROLLBACK 事務(wù)回滾后
  • TransactionPhase.AFTER_COMPLETION 事務(wù)完成后

使用TransactionPhase.AFTER_COMMIT可在事務(wù)完成后,再執(zhí)行事件監(jiān)聽(tīng)方法,從而保證數(shù)據(jù)的一致性

3. TransactionPhase.AFTER_ROLLBACK回滾事務(wù)問(wèn)題

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK, condition = "#departmentEvent.getState().toString() == 'SUCCEED'")
public void departmentCreatedFailed(DepartmentEvent departmentEvent) {
  System.err.println("dept-event3:" + departmentEvent);
}

由于@DomainEvents作用在實(shí)體上的,只有剛orderRepository.save(saleOrder)執(zhí)行成功后才會(huì)發(fā)送事件,故AFTER_ROLLBACK方法只會(huì)在同一事務(wù)中其它語(yǔ)句執(zhí)行失敗或顯式rollback時(shí)才會(huì)執(zhí)行,如果save方法執(zhí)行失敗,將不會(huì)監(jiān)聽(tīng)到回滾事件。

4. @Async異步事件監(jiān)聽(tīng)

  • 沒(méi)有此注解事件監(jiān)聽(tīng)方法與主方法為一個(gè)事務(wù)。
  • 使用此注解將脫離原有事務(wù),BEFORE_COMMIT也無(wú)法攔截事務(wù)提交前時(shí)刻
  • 此注解需要配合@EnableAsync一起使用

四、 總結(jié)

通過(guò)對(duì) @DomainEvents、@TransactionalEventListener的使用,在有效的解決領(lǐng)域事件發(fā)布的情況下,減少了對(duì)業(yè)務(wù)代碼的入侵,同時(shí)盡一步解決了數(shù)據(jù)一致性問(wèn)題。

在分布式結(jié)構(gòu)下,通過(guò)MQ發(fā)送事件通知給其它服務(wù),為解決一致性問(wèn)題,防止對(duì)方服務(wù)處理失敗可先將事件保久化到數(shù)據(jù)庫(kù)后,再重試。

五、 源碼

https://gitee.com/hypier/barry-jpa/tree/master/jpa-section-5

到此這篇關(guān)于詳解基于Spring Data的領(lǐng)域事件發(fā)布的文章就介紹到這了,更多相關(guān)Spring Data 領(lǐng)域事件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java對(duì)接支付寶支付接口簡(jiǎn)單步驟記錄

    java對(duì)接支付寶支付接口簡(jiǎn)單步驟記錄

    最近項(xiàng)目APP需要接入微信、支付寶支付功能,在分配開(kāi)發(fā)任務(wù)時(shí),聽(tīng)說(shuō)微信支付接口比支付寶支付接口要難實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于java對(duì)接支付寶支付接口的簡(jiǎn)單步驟,需要的朋友可以參考下
    2024-05-05
  • Java 泛型總結(jié)(三):通配符的使用

    Java 泛型總結(jié)(三):通配符的使用

    在泛型的使用中,還有個(gè)重要的東西叫通配符,本文介紹通配符的使用。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-03-03
  • Netty分布式NioSocketChannel注冊(cè)到selector方法解析

    Netty分布式NioSocketChannel注冊(cè)到selector方法解析

    這篇文章主要為大家介紹了Netty分布式源碼分析NioSocketChannel注冊(cè)到selector方法的解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • spring security與corsFilter沖突的解決方案

    spring security與corsFilter沖突的解決方案

    這篇文章主要介紹了spring security與corsFilter沖突的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java圖片轉(zhuǎn)字符圖片的生成方法

    Java圖片轉(zhuǎn)字符圖片的生成方法

    本文主要實(shí)現(xiàn)了將一張圖片轉(zhuǎn)成字符圖片,同樣可以遍歷每個(gè)像素點(diǎn),然后將像素點(diǎn)由具體的字符來(lái)替換,從而實(shí)現(xiàn)字符化處理,感興趣的可以了解一下
    2021-11-11
  • SpringBoot之那些注入不了的Spring占位符(${}表達(dá)式)問(wèn)題

    SpringBoot之那些注入不了的Spring占位符(${}表達(dá)式)問(wèn)題

    這篇文章主要介紹了SpringBoot之那些注入不了的Spring占位符(${}表達(dá)式)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • JAVA找不到符號(hào)的三種解決方案

    JAVA找不到符號(hào)的三種解決方案

    這篇文章主要給大家介紹了關(guān)于JAVA找不到符號(hào)的三種解決方案, 找不到符號(hào)錯(cuò)誤主要發(fā)生在我們?cè)噲D引用一個(gè)未在我們正在編譯的程序中聲明的變量時(shí),這意味著編譯器不知道我們所引用的Java變量,需要的朋友可以參考下
    2024-03-03
  • SpringBoot異步Async使用Future與CompletableFuture區(qū)別小結(jié)

    SpringBoot異步Async使用Future與CompletableFuture區(qū)別小結(jié)

    本文主要介紹了SpringBoot異步Async使用Future與CompletableFuture區(qū)別小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java排列組合字符串的方法

    Java排列組合字符串的方法

    這篇文章主要介紹了Java排列組合字符串的方法
    2018-02-02
  • 全面了解JAVA_BaseDAO數(shù)據(jù)處理類(lèi)

    全面了解JAVA_BaseDAO數(shù)據(jù)處理類(lèi)

    下面小編就為大家?guī)?lái)一篇全面了解JAVA_BaseDAO數(shù)據(jù)處理類(lèi)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07

最新評(píng)論

石狮市| 泸西县| 钦州市| 阿图什市| 乡宁县| 南雄市| 齐齐哈尔市| 济宁市| 苍山县| 屯留县| 阿瓦提县| 通江县| 贵港市| 肇源县| 渭源县| 平舆县| 武强县| 北海市| 务川| 苍山县| 兴海县| 太仆寺旗| 永德县| 平陆县| 张家界市| 永和县| 仪征市| 井研县| 前郭尔| 巫溪县| 互助| 锡林郭勒盟| 江川县| 大化| 敦化市| 廉江市| 江北区| 象州县| 临澧县| 惠东县| 荥阳市|