Software Architecture

Message/Event-driven Architecture

事件驱动

生活中的“事件驱动”

  • 银行存款:更新余额/用户等级提升/贷款广告推送
  • 信用卡消费:信用额度检查/风险控制/消费通知短信发送
  • 航班延误:广播通知乘客/后续行程更新/酒店订单更新

事件驱动架构

Event-driven architecture (EDA) is a software architecture paradigm promoting the production, detection, consumption of, and reaction to events.

An event can be defined as "a significant change in state".For example, when a consumer purchases a car, the car's state changes from "for sale" to "sold". A car dealer's system architecture may treat this state change as an event whose occurrence can be made known to other applications within the architecture.


https://en.wikipedia.org/wiki/Event-driven_architecture

事件驱动的GUI

事件驱动的调试器

事件驱动架构


Event:“a significant change in state”

  • Header: describing the event occurrence
    • Event type
    • Event name
    • Event timestamp
    • Event creator
  • Body: describing what is happening
    • The cause of why the event was triggered
    • The information about the event for the interested parties

松耦合

  • An Event Emitter does not know the consumers of the event, it does not even know if a consumer exists, and in case it exists, it does not know how the event is used or further processed.
  • Sinks have the responsibility of applying a reaction as soon as an event is presented.
  • The knowledge of the correct distribution of events is exclusively present within the event channel. The physical implementation of event channels can be based on traditional components such as message-oriented middleware or point-to-point communication.

Java AWT

  • Event sources
    • Button, Scrollbar, etc
  • Events
    • Mouse clicked/moved
    • Window resized/moved
    • Keyboard pressed/released

AWT 事件处理模型

  • 标准AWT Listener
    • ActionListener/AdjustmentListener/ComponentListener/…
  • 事件源在特定事件发生时会触发特定Listener的特定方法
  • 用户对于事件的处理包括两个步骤
    • 实现一个Listenser或继承一个Adapter
    • 利用事件源提供的addXXXListener来将自己实现的事件处理与事件源可能产生的事件绑定起来

AWT 示例

public class ClickReporter extends Applet {

    private static final long serialVersionUID = 1L;

    public void init() {
        setBackground(Color.yellow);
        addMouseListener(new ClickListener());
    }

     class ClickListener extends MouseAdapter {
        public void mousePressed(MouseEvent event) {
            System.out.println("Mouse pressed at (" + event.getX() + "," + event.getY() + ")");
        }
    }
   
}

另一版本

public class ClickReporter extends Applet implements MouseListener {
    public void init() {
        setBackground(Color.yellow);
        addMouseListener(this);
    }

    public void mouseEntered(MouseEvent event) { }

    public void mouseExited(MouseEvent event) { }

    public void mouseReleased(MouseEvent event) { }

    public void mouseClicked(MouseEvent event) { }

    public void mousePressed(MouseEvent event) {
        System.out.println("Mouse pressed at (" + event.getX() + "," + event.getY() + ")");
    }
}

Java Swing

public class FooPanel extends JPanel implements ActionListener {
    public FooPanel() {
        super();

        JButton btn = new JButton("Click Me!");
        btn.addActionListener(this);

        this.add(btn);
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        System.out.println("Button has been clicked!");
    }
}

观察者模式


https://en.wikipedia.org/wiki/Observer_pattern

发布/订阅模式


https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c

Guava EventBus

https://www.bilibili.com/video/BV1Wa4y1477d?p=2 10:40

sa-spring/guava-eventbus

Guava: Google Core Libraries for Java https://github.com/google/guava

观察者 vs 发布/订阅

Spring Events

Event handling in the ApplicationContext is provided through the ApplicationEvent class and the ApplicationListener interface.

If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified.

Essentially, this is the standard Observer design pattern.

Standard Events

  • ContextRefreshedEvent
  • ContextStartedEvent
  • ContextStoppedEvent
  • ContextClosedEvent
  • RequestHandledEvent
  • ServletRequestHandledEvent
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#context-functionality-events

Example & Demo

import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
    @EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
    public void handleContextStart() {
        System.out.print("Application Context Started");
    }
}

https://www.bilibili.com/video/BV1Wa4y1477d?p=3 3:50

sa-spring/spring-events

Asynchronous Listeners

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#context-functionality-events-async

Ordering Listeners

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#context-functionality-events-order

Advance Event Channel

Event channels are conduits in which events are transmitted from event emitters to event consumers. … The physical implementation of event channels can be based on traditional components such as message-oriented middleware


Message-oriented middleware (MOM) is software or hardware infrastructure supporting sending and receiving messages between distributed systems.
https://en.wikipedia.org/wiki/Message-oriented_middleware

Message-oriented middleware

AMQP

高级消息队列协议即Advanced Message Queuing Protocol是面向消息中间件提供的开放的应用层协议,其设计目标是对于消息的排序、路由、保持可靠性、保证安全性。


https://www.amqp.org/

RabbitMQ

https://www.rabbitmq.com/

RabbitMQ

  1. The producer publishes a message to the exchange.
  2. The exchange receives the message and is responsible for the routing of the message.
  3. Binding must be set up between the queue and the exchange. Here we have bindings to two different queues which exchange routes the message into.
  4. The messages stay in the queue until they are handled by a consumer.
  5. The consumer handles the message.

Types of Exchanges

Types Explaination

Spring AMQP

  • AMQP entities – we create entities with the Message, Queue, Binding, and Exchanges classes
  • Connection Management – we connect to our RabbitMQ broker by using a CachingConnectionFactory
  • Message Publishing – we use a RabbitTemplate to send messages
  • Message Consumption – we use a @RabbitListener to read messages from a queue

Spring AMQP Demo

https://www.bilibili.com/video/BV1Wa4y1477d?p=4 3:10

sa-spring/spring-amqp

docker run -d -p 5672:5672 -p 15672:15672 --name my-rabbit rabbitmq:3-management

http://localhost:15672

Event-driven systems

Event-driven systems reflect how modern businesses actually work–thousands of small changes happening all day, every day.

Spring’s ability to handle events and enable developers to build applications around them, means your apps will stay in sync with your business.

Event-driven Spring Applications

Spring has a number of options to choose from, from integration and streaming all the way to cloud functions and data flows.

  • Event-driven microservices
  • Streaming data
  • Integration

Event-driven microservices

https://spring.io/blog/2019/10/15/simple-event-driven-microservices-with-spring-cloud-stream

Spring Cloud Stream

Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.

The framework provides a flexible programming model built on already established and familiar Spring idioms and best practices, including support for persistent pub/sub semantics, consumer groups, and stateful partitions.

https://spring.io/projects/spring-cloud-stream

Binder

Spring Cloud Stream supports a variety of binder implementations.

  • RabbitMQ
  • Apache Kafka
  • Google PubSub
  • ...
sa-spring/stream-loan

Event-driven MicroPoS

--- # 反转控制关系 ![height:350px](images/10-ioc.png) Hollywood Principle :"don't call us, we'll call you." ![bg right:50% 90%](images/10-event-driven-debugger.png)