每篇一句
人可以有追求,但切莫攀比。你虚荣可以,但一定要靠自己。父母给的是后盾,你自己打的才叫江山
相关阅读
【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)
【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动/刷新的完整总结
前言
说到事件驱动,我心里一直就有一个不解的疑问:它和我们老生长谈的一些概念比如:【观察者模式】【发布订阅模式】【消息队列MQ】【消息驱动】【EventSourcing】等等是一回事吗?
可能很多小伙伴会回答:差不多
。确实,很有深意的三字回答。
那么本文将以Spring的事件驱动机制为引子,好好的聊聊这里面的关系和差异~
JDK中的事件驱动机制
在了解其它之前,有必要先了解下JDK为我们提供的事件驱动(EventListener、EventObject
)、观察者模式(Observer
)。
JDK不仅提供了Observable
类、Observer
接口支持观察者模式,而且也提供了EventObject
、EventListener
接口来支持事件监听模式。
这些类都属于
java.util
下的
观察者模式(Observable
和Observer
) JDK1.0提供
被观察对象:观察者 = 1:n (观察者可以有N个嘛)
观察者(Observer)相当于事件监听者(监听器),被观察者(Observable
)相当于事件源和事件,执行逻辑时通知observer即可触发oberver的update,同时可传被观察者和参数。简化了事件-监听模式的实现。
// 观察者,实现此接口即可
public interface Observer {
// 当被观察的对象发生变化时候,这个方法会被调用
//Observable o:被观察的对象
// Object arg:传入的参数
void update(Observable o, Object arg);
}
// 它是一个Class
public class Observable {
// 是否变化,决定了后面是否调用update方法
private boolean changed = false;
// 用来存放所有`观察自己的对象`的引用,以便逐个调用update方法
// 需要注意的是:1.8的jdk源码为Vector(线程安全的),有版本的源码是ArrayList的集合实现;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o); //添加一个观察者 注意调用的是addElement方法,添加到末尾 所以执行时是倒序执行的
public synchronized void deleteObserver(Observer o);
public synchronized void deleteObservers(); //删除所有的观察者
// 循环调用所有的观察者的update方法
public void notifyObservers();
public void notifyObservers(Object arg);
public synchronized int countObservers() {
return obs.size();
}
// 修改changed的值
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
}
它的使用非常的便捷,看个例子就能明白;
class Person extends Observable {
public String name;
public Person(String name) {
this.name = name;
}
// 给鱼:这样所有观察的猫都会过来了
// fishType: 鱼的名字
public void giveFish(String fishName) {
setChanged(); // 这个一定不能忘
notifyObservers(fishName);
}
}
class Cat implements Observer {
public String name;
public Cat(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
String preffix = o.toString();
if (o instanceof Person) {
preffix = ((Person) o).name;
}
System.out.println(preffix + "主人放 " + arg + "~了," + name + "去吃鱼吧");
}
}
// 测试方法如下:
public static void main(String[] args) {
Person person = new Person("fsx");
// 来10只猫 观察这个人
for (int i = 0; i < 10; i++) {
person.addObserver(new Cat("cat" + i));
}
//开始放fish,这时候观察的猫就应该都过来了
person.giveFish("草鱼");
}
// 输出
fsx主人放 草鱼~了,cat9去吃鱼吧
fsx主人放 草鱼~了,cat8去吃鱼吧
fsx主人放 草鱼~了,cat7去吃鱼吧
fsx主人放 草鱼~了,cat6去吃鱼吧
fsx主人放 草鱼~了,cat5去吃鱼吧
fsx主人放 草鱼~了,cat4去吃鱼吧
fsx主人放 草鱼~了,cat3去吃鱼吧
fsx主人放 草鱼~了,cat2去吃鱼吧
fsx主人放 草鱼~了,cat1去吃鱼吧
fsx主人放 草鱼~了,cat0去吃鱼吧
JDK的观察者模式使用起来确实非常的方便,我们只需要面对两个对象即可。内部观察者队列啥的都交给
Observable
去处理了。并且,它是线程安全的
发布订阅模式(EventListener
和EventObject
) JDK1.1提供
Spring中的事件驱动机制
事件机制一般包括三个部分:EventObject,EventListener和Source
。
EventObject
:事件状态对象的基类,它封装了事件源对象以及和事件相关的信息。所有java的事件类都需要继承该类
EventListener
:是一个标记接口,就是说该接口内是没有任何方法的。所有事件监听器都需要实现该接口。事件监听器注册在事件源上,当事件源的属性或状态改变的时候,调用相应监听器内的回调方法
(自己写)。
Source
:一个普通的POJO。事件最初发生的地方,他里面必须含有监听它的监听器们
class MyEvent extends EventObject {
public MyEvent(Object source) {
super(source);
}
}
// 状态改变事件
class StatusChangedListener implements EventListener {
public void handleEvent(MyEvent event) {
System.out.println(event.getSource() + " 的状态改变啦~");
}
}
// 状态没变化事件
class StateSameListener implements EventListener {
public void handleEvent(MyEvent event) {
System.out.println(event.getSource() + " 的状态没有任何变化~");
}
}
class MySource {
private int status;
List<EventListener> eventListeners = new ArrayList<>();
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public void addListener(EventListener listener) {
eventListeners.add(listener);
}
// 调用所有的合适的监听器
public void notifyListeners(int oldStatus, int newStatus) {
eventListeners.forEach(l -> {
if (oldStatus == newStatus) {
// doSamething
} else {
// doSamething
}
});
}
}
// 测试方法
public static void main(String[] args) {
MySource mySource = new MySource();
mySource.addListener(new StatusChangedListener());
mySource.addListener(new StateSameListener());
int oldStatus = mySource.getStatus();
mySource.setStatus(1);
int newStatus = mySource.getStatus();
// 触发所有的监听者们
mySource.notifyListeners(oldStatus, newStatus);
}
对弈上面的观察者模式,监听模式使用起来确实非常的繁琐,且还线程安全问题
还得自己考虑解决。我个人觉得JDK的源生的事件、监听模式非常难用(不太建议使用,它最大的败笔在于EventListener
接口没有定义一个抽象方法,不知道是作何考虑的,应该是为了更加抽象吧)。因此接下来,大行其道的Spring事件机制就很好的解决使用上的问题~~~它也是今天的主菜
Spring中事件驱动机制
Spring提供了ApplicationEventPublisher
接口作为事件发布者(ApplicationContext接口继承了该接口
,担当着事件发布者的角色)。
Spring提供了ApplicationEventMulticaster
接口,负责管理ApplicationListener
和真正发布ApplicationEvent
(ApplicationContext
是委托给它完成的)
ApplicationListener
实现了JDK的EventListener
,但它抽象出一个onApplicationEvent
方法,使用更方便。ApplicationEvent
继承自EventObject
。 Spring这么做我觉得完全是为了兼容Java规范~
在博文:【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动/刷新的完整总结
这里讲解IoC容器refresh()
的时候,第八步:initApplicationEventMulticaster()
和第十步:registerListeners()
和第十二步:inishRefresh()方法里的publishEvent(new ContextRefreshedEvent(this))
都是和时间机制相关的方法。
initApplicationEventMulticaster()
:我们向容器注册了一个SimpleApplicationEventMulticaster
(若我们自己没指定的话),因此若我们希望手动控制时间的发布,是可以@Autowired
进来的
registerListeners()
:会把所有的ApplicationListener
添加进ApplicationEventMulticaster
进行管理(注意此处并不包括@EventListener
标注的注解方法)
publishEvent
:发布事件。因为ApplicationContext
继承了ApplicationEventMulticaster
,因此我们一般发布时间建议用它就成了
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 此子接口提供了泛型,和提供了统一的处理方法
void onApplicationEvent(E event);
}
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 这个接口是Spring4.2后提供的,可以发布任意的事件对象(即使不是ApplicationEvent的子类了)
// 当这个对象不是一个ApplicationEvent,我们会使用PayloadApplicationEvent来包装一下再发送
// 比如后面会建讲到的@EventListener注解标注的放 就是使用的它
void publishEvent(Object event);
}
我们知道Spring4.2后提供了@EventListener
注解,让我们更便捷的使用监听了,非常非常非常的方便:
ApplicationListener
实现类模式的演示和原理解析
这是Spring最早期就提供了的一种事件监听方式。实现起来也非常的简单。
通过Spring源码我们了解到,Spring容器刷新的时候会发布ContextRefreshedEvent
事件,因此若我们需要监听此事件,直接写个监听类即可:
@Slf4j
@Component
public class ApplicationRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Object source = event.getSource();
// 此处的source就是ApplicationContext这个对象
System.out.println(source); //WebApplicationContext for namespace 'dispatcher-servlet': startup date [Tue Mar 26 14:26:27 CST 2019]; parent: Root WebApplicationContext
//容器此时已经准备好了,可以做你该做的事了~......(请注意:若存在父子容器或者多个容器情况,此方法会被执行多次,请务必注意是否幂等)
}
}
若是web环境,FrameworkServlet在处理完每一次i请求,也会发出一个事件:
ServletRequestHandledEvent
自己发布一个事件,然后自己监听~~~~
public class MyAppEvent extends ApplicationEvent {
public MyAppEvent(Object source) {
super(source);
}
}
// 写个监听器,然后交给容器管理即可
@Slf4j
@Component
public class MyEventListener implements ApplicationListener<MyAppEvent> {
@Override
public void onApplicationEvent(MyAppEvent event) {
Object source = event.getSource();
long timestamp = event.getTimestamp();
System.out.println(source);
System.out.println(timestamp);
//doSomething
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 发布自己的事件
applicationContext.publishEvent(new MyAppEvent("this is my event"));
}
// 输出:
this is my event
1553581974928
Spring内置的事件讲解
Web相关事件:
RequestHandledEvent
:Web相关事件,只能应用于使用DispatcherServlet
的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件(即ServletRequestHandledEvent
)
ApplicationContextEvent:应用本身的事件
ContextRefreshedEvent
:容器初始化完成刷新时触发。此时所有的Bean已经初始化完成、后置处理器等都已经完成ContextStartedEvent
:AbstractApplicationContext#strart()
被调用时。 需要手动调用,个人觉得没啥卵用ContextStoppedEvent
:容器的stop方法被手动调用时。 也没啥卵用ContextClosedEvent
:close() 关闭容器时候发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
@EventListener
注解方法模式演示和原理解析
在任意方法上标注@EventListener
注解,指定 classes,即需要处理的事件类型,一般就是 ApplicationEven 及其子类(当然任意事件也是Ok的,比如下面的MyAppEvent
就是个普通的POJO),可以设置多项。
public class MyAppEvent {
private String name;
public MyAppEvent(String name) {
this.name = name;
}
}
// 显然此处,它会收到两个时间,分别进行处理
@Component
public class MyAllEventListener {
//value必须给值,但可以不用是ApplicationEvent的子类 任意事件都ok
// 也可以给一个入参,代表事件的Event
@EventListener(value = {ContextRefreshedEvent.class, MyAppEvent.class}
// confition的使用,若同一个事件进行区分同步异步 等等条件的可以使用此confition 支持spel表达式 非常强大
/*,condition = "#event.isAsync == false"*/)
public void handle(Object o) {
System.out.println(o);
System.out.println("事件来了~");
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 发布自己的事件
applicationContext.publishEvent(new MyAppEvent("this is my event"));
}
显然这种方式更被推崇,因为它是方法级别的,更轻便了。(Spring4.2之后提出)
Spring事件机制原理分析
事件收集(EventListenerMethodProcessor
)
事件的收集前面讲了继承ApplicationListener
的收集情况,那么此处就重点说说Spring4.2后提供的关于@EventListener
注解的情况,看看Spring是怎么收集到这些方法,然后管理起来的。
一切源于Spring容器启动过程中:AnnotationConfigUtils.registerAnnotationConfigProcessors(context)
注册的7大基础组件时,其中有一个是EventListenerMethodProcessor
,它就是处理EventListener
注解然后把它注册为一个特别的ApplicationListener
的处理器。 当然还有一个EventListenerFactory(DefaultEventListenerFactory)
// 它是一个SmartInitializingSingleton,所以他会在preInstantiateSingletons()的最后一步执行~~~
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {
@Nullable
private ConfigurableApplicationContext applicationContext;
// 解析注解中的Conditon的
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
// 视图 这样set也变成线程安全的了
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
@Override
public void afterSingletonsInstantiated() {
// 从容器里获得所有的EventListenerFactory,它是用来后面处理标注了@EventListener方法的工厂(Spring默认放置的是DefaultEventListenerFactory,我们也可以继续放 支持@Order等注解)
List<EventListenerFactory> factories = getEventListenerFactories();
ConfigurableApplicationContext context = getApplicationContext();
// 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~ 一个一个的检查
String[] beanNames = context.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
// 不处理Scope作用域代理的类。 和@Scope类似相关
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
// 防止是代理,吧真实的类型拿出来
type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
}
if (type != null) {
// 对专门的作用域对象进行兼容~~~~(绝大部分都用不着)
if (ScopedObject.class.isAssignableFrom(type)) {
...
}
// 真正处理这个Bean里面的方法们。。。
processBean(factories, beanName, type);
}
}
}
}
protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
// 缓存下没有被注解过的Class,这样再次解析此Class就不用再处理了
//这是为了加速父子容器的情况 做的特别优化
if (!this.nonAnnotatedClasses.contains(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// 这可以说是核心方法,就是找到这个Class里面被标注此注解的Methods们
// 在讲述到反射专题的时候,相关方法会再具体分析
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
// 若一个都没找到,就缓存起来,然后结束呗~~~~~~~~~~~~~~~~~~~~~
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = getApplicationContext();
// 处理这些带有@EventListener注解的方法们
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
// 加工的工厂类也可能有多个,但默认只有Spring注册给我们的一个
// supportsMethod表示是否支持去处理此方法(因为我们可以定义处理器,只处理指定的Method都是欧克的) Spring默认实现永远返回true
if (factory.supportsMethod(method)) {
// 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关)
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 把这个方法包装成一个监听器ApplicationListener(ApplicationListenerMethodAdapter类型)
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
// 这个init方法是把ApplicationContext注入进去
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 添加进去 管理起来
context.addApplicationListener(applicationListener);
break;
}
}
}
}
}
}
}
就着这样,最终我们所有的Listener
都被管理了起来。
事件发布(SimpleApplicationEventMulticaster
)
我们一般都会使用AbstractApplicationContext#publish()
来发布一个事件:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
// 如果这个事件不是ApplicationEvent类型,那就包装成这个类型
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
// 注意此处:第一个参数为source,这里传的source,第二个是payload,才传的是事件本身
applicationEvent = new PayloadApplicationEvent<>(this, event);
// 若没有指定类型。就交给PayloadApplicationEvent<T>,它会根据泛型类型生成出来的~~~
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// 如果是早期事件,就添加进去 会立马发布了(一般都不属于这种)
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
// 最终把这些时间都委派给了`ApplicationEventMulticaster` 让它去发送事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 此处注意:特别重要,如果是父容器,也会向父容器里广播一份~~~~~
if (this.parent != null) {
// 这个判断的用意是,既然eventType已经解析出来了,所以就调用protected内部方法即可,而不用再次解析一遍了
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
// 如果是普通的发布,就没有eventType了
else {
this.parent.publishEvent(event);
}
}
}
因此重点看看ApplicationEventMulticaster#multicastEvent
:它的唯一实现为:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 若set了一个执行器,那所有的监听器都将会异步执行
@Nullable
private Executor taskExecutor;
// 监听者执行失败的回调~~~~~~(比如做回滚等等)
@Nullable
private ErrorHandler errorHandler;
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 这里面有个细节:如果有执行器executor ,那就会扔给线程池异步去执行
// 默认情况下是没有的(Spring默认情况下同步执行这些监听器的) 我们可以调用set方法配置一个执行器(建议)
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 如果是实现了ApplicationListener接口,则直接调用其中的onApplicationEvent()方法;
//如果是用@EventListener注释,则调用ApplicationListenerMethodAdapter中的onApplicationEvent()方法
listener.onApplicationEvent(event);
}
}
ApplicationListenerMethodAdapter#onApplicationEvent
:
@Override
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
public void processEvent(ApplicationEvent event) {
// 获取参数,最终会交给回调的方法的。事件类型是PayloadApplicationEvent,那就把.getPayload(),否则就是event本身喽
Object[] args = resolveArguments(event);
// 解析condition表达式(注意,此处把args传进去了) 因此我们表达式里是可以用这个参数的哦
if (shouldHandle(event, args)) {
// 就是执行目标方法,我们一般返回值都是void,所以就是null
// 但是,但是,但是注意了,此处若返回的不是null,还有处理~~~~非常给力:
Object result = doInvoke(args);
if (result != null) {
// 如果返回值是数组或者Collection,会把里面内容当作事件循环publishEvent
// 如果就是个POJO,那就直接publish
// 事件的传递性 就这么的来了,强大啊
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
Spring的使用
@EventListener
监听事件。若监听方法有返回值,那将会把这个返回值当作事件源,一直发送下去,直到返回void或者null
停止
@EventListener(value = {ContextRefreshedEvent.class})
public List<Child> handle(Object o) {
List<Child> childList = new ArrayList<>();
childList.add(new Child("1"));
childList.add(new Child("2"));
return childList;
}
// 因为上个方法有返回 所以事件会传递到此处
@EventListener(Child.class)
public void handChild(Child c) {
System.out.println(c.getName() + " 发来了事件");
}
输出:
1 发来了事件
2 发来了事件
Spring事件传递的应用场景,巧妙的使用,可以事半功倍。(当然必须了解原理,才能运用自如)
@EventListener
使用中的小细节
@EventListener
注解用在接口或者父类
上都是没有任何问题的(这样子类就不用再写了,在接口层进行控制)@EventListener
标注的方法,无视访问权限AbstractApplicationEventMulticaster
的相关方法比如addApplicationListenerBean、removeApplicationListener。。。
都是线程安全的。- 若想要异步执行事件,请自己配置@Bean这个Bean。然后
setTaskExecutor()
一个进去
@Component
public class MyAllEventListener implements MyAllEventListenerInterface {
@Override
public void handChild(Child c) {
System.out.println(c.getName() + " 发来了事件");
}
}
// 注解写在接口上,也是能正常work的~~~
interface MyAllEventListenerInterface {
@EventListener(Child.class)
void handChild(Child c);
}
各大模式大比拼
观察者模式
:它是设计模式里的一个术语。是一个非常经典的行为型设计模式。。猫叫了,主人醒了,老鼠跑了,这一经典的例子,是事件驱动模型在设计层面的体现。发布订阅模式
:很多人认为等同于观察者模式。但我的理解是两者唯一区别,是发布订阅模式需要有一个调度中心
,而观察者模式不需要(观察者的列表可以直接由被观察者维护)。 但它俩混用没问题,一般都不会在表达上有歧义消息队列MQ
:中间件级别的消息队列(ActiveMQ,RabbitMQ
),可以认为是发布订阅模式的一个具体体现
事件驱动->发布订阅->MQ,从抽象到具体。 因此MQ算是一个落地的产品了
EventSourcing
:这个要关联到领域驱动设计。DDD对事件驱动也是非常地青睐,领域对象的状态完全是由事件驱动来控制。比如有著名的CQRS架构~~~
CQRS架构和微服务的关系:微服务的目的是为了从业务角度拆分(
职责分离
)当前业务领域的不同业务模块到不同的服务,每个微服务之间的数据完全独立
,它们之间的交互可以通过SOA RPC
调用(耦合比较高),也可以通过EDA
消息驱动(耦合比较低,比如我们常用的分布式产品:MQ)。
这类模式的优缺点
有点:
- 支持简单的广播通信,自动通知所有已经订阅过的对象
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用(保持职责单一,解耦)
- 观察者模式分离了观察者和被观察者二者的责任,这样让类之间各自维护自己的功能,专注于自己的功能,会提高系统的可维护性和可重用性。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
总结
本文暂时只介绍了Spring中的一些简单的事件驱动机制,相信如果之后再看到Event,Publisher,EventListener
·一类的单词后缀时,也能立刻和事件机制联系上了
知识交流
若群二维码失效,请加微信号(或者扫描下方二维码):fsx641385712。
并且备注:“java入群” 字样,会手动邀请入群