美文网首页Design Pattern MySQL
Spring Event-Driven Architecture

Spring Event-Driven Architecture

作者: 但时间也偷换概念 | 来源:发表于2021-06-20 16:18 被阅读0次

    前言

    Spring Event-Driven 是Java生态中关于Event-Driven编程范式的最佳实践标准之一 ,在Spring框架之前,已经有JDK、Servlet、EJB等框架进行过观察者模式、事件驱动、注解式监听等尝试,本文简要分析一下Spring在事件驱动方面的设计。

    从观察者模式说起

    Pub-Sub设计模式应该是由观察者模式变种而来 ,所以我们有必要了解一下在JDK中提供的Observable/Observer实现标准。

    pacakge java.util;
    
    public class Observable {
        private boolean changed = false;
        private Vector<Observer> obs;
    
        /** Construct an Observable with zero Observers. */
    
        public Observable() {
            obs = new Vector<>();
        }
    
        /**
         * Adds an observer to the set of observers for this object, provided
         * that it is not the same as some observer already in the set.
         * The order in which notifications will be delivered to multiple
         * observers is not specified. See the class comment.
         *
         * @param   o   an observer to be added.
         * @throws NullPointerException   if the parameter o is null.
         */
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        /**
         * Deletes an observer from the set of observers of this object.
         * Passing <CODE>null</CODE> to this method will have no effect.
         * @param   o   the observer to be deleted.
         */
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        /**
         * If this object has changed, as indicated by the
         * <code>hasChanged</code> method, then notify all of its observers
         * and then call the <code>clearChanged</code> method to
         * indicate that this object has no longer changed.
         * <p>
         * Each observer has its <code>update</code> method called with two
         * arguments: this observable object and <code>null</code>. In other
         * words, this method is equivalent to:
         * <blockquote><tt>
         * notifyObservers(null)</tt></blockquote>
         *
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#hasChanged()
         * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
         */
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        /**
         * If this object has changed, as indicated by the
         * <code>hasChanged</code> method, then notify all of its observers
         * and then call the <code>clearChanged</code> method to indicate
         * that this object has no longer changed.
         * <p>
         * Each observer has its <code>update</code> method called with two
         * arguments: this observable object and the <code>arg</code> argument.
         *
         * @param   arg   any object.
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#hasChanged()
         * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
         */
        public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                /* We don't want the Observer doing callbacks into
                 * arbitrary code while holding its own Monitor.
                 * The code where we extract each Observable from
                 * the Vector and store the state of the Observer
                 * needs synchronization, but notifying observers
                 * does not (should not).  The worst result of any
                 * potential race-condition here is that:
                 * 1) a newly-added Observer will miss a
                 *   notification in progress
                 * 2) a recently unregistered Observer will be
                 *   wrongly notified when it doesn't care
                 */
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
        /**
         * Clears the observer list so that this object no longer has any observers.
         */
        public synchronized void deleteObservers() {
            obs.removeAllElements();
        }
    
        /**
         * Marks this <tt>Observable</tt> object as having been changed; the
         * <tt>hasChanged</tt> method will now return <tt>true</tt>.
         */
        protected synchronized void setChanged() {
            changed = true;
        }
    
        /**
         * Indicates that this object has no longer changed, or that it has
         * already notified all of its observers of its most recent change,
         * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
         * This method is called automatically by the
         * <code>notifyObservers</code> methods.
         *
         * @see     java.util.Observable#notifyObservers()
         * @see     java.util.Observable#notifyObservers(java.lang.Object)
         */
        protected synchronized void clearChanged() {
            changed = false;
        }
    
        /**
         * Tests if this object has changed.
         *
         * @return  <code>true</code> if and only if the <code>setChanged</code>
         *          method has been called more recently than the
         *          <code>clearChanged</code> method on this object;
         *          <code>false</code> otherwise.
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#setChanged()
         */
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        /**
         * Returns the number of observers of this <tt>Observable</tt> object.
         *
         * @return  the number of observers of this object.
         */
        public synchronized int countObservers() {
            return obs.size();
        }
    }
    
    
    package java.util;
    
    /**
     * A class can implement the <code>Observer</code> interface when it
     * wants to be informed of changes in observable objects.
     *
     * @author  Chris Warth
     * @see     java.util.Observable
     * @since   JDK1.0
     */
    public interface Observer {
        /**
         * This method is called whenever the observed object is changed. An
         * application calls an <tt>Observable</tt> object's
         * <code>notifyObservers</code> method to have all the object's
         * observers notified of the change.
         *
         * @param   o     the observable object.
         * @param   arg   an argument passed to the <code>notifyObservers</code>
         *                 method.
         */
        void update(Observable o, Object arg);
    }
    
    




    如上图,JDK推荐我们基于Observable和Observer拓展来进行观察者模式编码。
    实践代码如下:

    public class ObserverDemo {
    
        public static void main(String[] args) {
            EventObservable eventObservable = new EventObservable();
    
            eventObservable.addObserver(new EventObserver());
            eventObservable.notifyObservers("hello world");
        }
    
        static class EventObservable extends Observable {
            @Override
            public void notifyObservers(Object payload) {
                setChanged();
                super.notifyObservers(payload);
                clearChanged();
            }
        }
    
        static class EventObserver implements Observer {
    
            @Override
            public void update(Observable o, Object payload) {
                System.out.println("Receive message :" + payload);
            }
        }
    }
    
    

    如上图,简单分析一下,这一套标准蹩脚的地方在于:

    1. Observable进行notify的时候,必须要setChanged状态,才能真正被观察到,否则会忽略掉变化,直接被return了,具体见源码如下:
     public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
    
    1. setChanged方法是个protected级别 ,必须得继承一个Observable才能玩。
      如下:
        protected synchronized void setChanged() {
            changed = true;
        }
    
    

    所以整体封装成如下代码:

       static class EventObservable extends Observable {
            @Override
            public void notifyObservers(Object payload) {
                setChanged();
                super.notifyObservers(payload);
                clearChanged();
            }
        }
    
    1. 拓展性太差

    综上所述,JDK 9版本官方直接推荐使用java.util.concurrent.Flow ,意思是让你别玩这个Observable了。

    事件驱动的模型

    上面提到了Observable/Observer模型 ,接下来说一说Event-Driven方面在Spring之前前人有过哪些尝试,相应的事件编程模型是什么样的。

    从监听粒度上分为单事件监听和多事件监听

    • 单事件监听模型
      指的是一个Listener一次只消费一个事件,比如Java Beans:
    public interface PropertyChangeListener extends java.util.EventListener {
    
        /**
         * This method gets called when a bound property is changed.
         * @param evt A PropertyChangeEvent object describing the event source
         *          and the property that has changed.
         */
    
        void propertyChange(PropertyChangeEvent evt);
    
    }
    
    
    • 多事件监听模型
      指的是一个Listener同时监听多个事件,比如AWT、Android中
    public interface MouseListener extends EventListener {
    
        /**
         * Invoked when the mouse button has been clicked (pressed
         * and released) on a component.
         */
        public void mouseClicked(MouseEvent e);
    
        /**
         * Invoked when a mouse button has been pressed on a component.
         */
        public void mousePressed(MouseEvent e);
    
        /**
         * Invoked when a mouse button has been released on a component.
         */
        public void mouseReleased(MouseEvent e);
    
        /**
         * Invoked when the mouse enters a component.
         */
        public void mouseEntered(MouseEvent e);
    
        /**
         * Invoked when the mouse exits a component.
         */
        public void mouseExited(MouseEvent e);
    }
    
    



    从监听者注册方式来区分,分为接口式和注解式。

    • 接口式
      顾名思义就是通过接口实现的方式,通过addListener的方式注册。
           context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
                @Override
                public void onApplicationEvent(ApplicationEvent event) {
                    System.out.println("Receive event : " + event);
                }
            });
    
    
    • 注解式
      顾名思义就是用注解指定Listener ,在Spring之前已经有开源产品这么玩过了。
      如Servlet 3.0 WebListener、JPA、jdk PostConstruct、EJB等注解。
        @EventListener
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("@EventListener Receive event : " + event);
        }
    

    JDK中的事件驱动规范

    在Java中,规范要求事件驱动模型是基于以下两个类去拓展的。

    package java.util;
    
    /**
     * <p>
     * The root class from which all event state objects shall be derived.
     * <p>
     * All Events are constructed with a reference to the object, the "source",
     * that is logically deemed to be the object upon which the Event in question
     * initially occurred upon.
     *
     * @since JDK1.1
     */
    
    public class EventObject implements java.io.Serializable {
    
        private static final long serialVersionUID = 5516075349620653480L;
    
        /**
         * The object on which the Event initially occurred.
         */
        protected transient Object  source;
    
        /**
         * Constructs a prototypical Event.
         *
         * @param    source    The object on which the Event initially occurred.
         * @exception  IllegalArgumentException  if source is null.
         */
        public EventObject(Object source) {
            if (source == null)
                throw new IllegalArgumentException("null source");
    
            this.source = source;
        }
    
        /**
         * The object on which the Event initially occurred.
         *
         * @return   The object on which the Event initially occurred.
         */
        public Object getSource() {
            return source;
        }
    
        /**
         * Returns a String representation of this EventObject.
         *
         * @return  A a String representation of this EventObject.
         */
        public String toString() {
            return getClass().getName() + "[source=" + source + "]";
        }
    }
    
    
    
    package java.util;
    
    /**
     * A tagging interface that all event listener interfaces must extend.
     * @since JDK1.1
     */
    public interface EventListener {
    }
    
    



    可以看到,关于事件驱动并没有给出任何实现,只是定义了标准的事件模型和监听标准,EventListner就有点类似于ArrayList实现了RamdomAccess标记。

    Spring事件模型

    了解以上背景以后,我们可以揭开Spring编程模型的面纱了,实际上正是基于前人的基础上设计。

    
    package org.springframework.context;
    
    import java.util.EventListener;
    
    /**
     * Interface to be implemented by application event listeners.
     *
     * <p>Based on the standard {@code java.util.EventListener} interface
     * for the Observer design pattern.
     *
     * <p>As of Spring 3.0, an {@code ApplicationListener} can generically declare
     * the event type that it is interested in. When registered with a Spring
     * {@code ApplicationContext}, events will be filtered accordingly, with the
     * listener getting invoked for matching event objects only.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @param <E> the specific {@code ApplicationEvent} subclass to listen to
     * @see org.springframework.context.ApplicationEvent
     * @see org.springframework.context.event.ApplicationEventMulticaster
     * @see org.springframework.context.event.EventListener
     */
    @FunctionalInterface
    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
        /**
         * Handle an application event.
         * @param event the event to respond to
         */
        void onApplicationEvent(E event);
    
    }
    
    
    /*
     * Copyright 2002-2019 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context;
    
    import java.util.EventObject;
    
    /**
     * Class to be extended by all application events. Abstract as it
     * doesn't make sense for generic events to be published directly.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @see org.springframework.context.ApplicationListener
     * @see org.springframework.context.event.EventListener
     */
    public abstract class ApplicationEvent extends EventObject {
    
        /** use serialVersionUID from Spring 1.2 for interoperability. */
        private static final long serialVersionUID = 7099057708183571937L;
    
        /** System time when the event happened. */
        private final long timestamp;
    
    
        /**
         * Create a new {@code ApplicationEvent}.
         * @param source the object on which the event initially occurred or with
         * which the event is associated (never {@code null})
         */
        public ApplicationEvent(Object source) {
            super(source);
            this.timestamp = System.currentTimeMillis();
        }
    
    
        /**
         * Return the system time in milliseconds when the event occurred.
         */
        public final long getTimestamp() {
            return this.timestamp;
        }
    
    }
    
    



    正是一个标准的java.util事件编程模型拓展,而Spring在此基础上做了进一步拓展,加入了时间戳。
    并且还有Spring特有的Context事件模型如下:

    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationEvent;
    
    /**
     * Base class for events raised for an {@code ApplicationContext}.
     *
     * @author Juergen Hoeller
     * @since 2.5
     */
    @SuppressWarnings("serial")
    public abstract class ApplicationContextEvent extends ApplicationEvent {
    
        /**
         * Create a new ContextStartedEvent.
         * @param source the {@code ApplicationContext} that the event is raised for
         * (must not be {@code null})
         */
        public ApplicationContextEvent(ApplicationContext source) {
            super(source);
        }
    
        /**
         * Get the {@code ApplicationContext} that the event was raised for.
         */
        public final ApplicationContext getApplicationContext() {
            return (ApplicationContext) getSource();
        }
    
    }
    
    

    可以看到ApplicationContextEvent在ApplicationEvent基础上,又增加了ApplicationContext对象进来,这是为了传递Spring容器上下文,基于这个上下文事件有四个标准内置事件。

    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationContext;
    
    /**
     * Event raised when an {@code ApplicationContext} gets initialized or refreshed.
     *
     * @author Juergen Hoeller
     * @since 04.03.2003
     * @see ContextClosedEvent
     */
    @SuppressWarnings("serial")
    public class ContextRefreshedEvent extends ApplicationContextEvent {
    
        /**
         * Create a new ContextRefreshedEvent.
         * @param source the {@code ApplicationContext} that has been initialized
         * or refreshed (must not be {@code null})
         */
        public ContextRefreshedEvent(ApplicationContext source) {
            super(source);
        }
    
    }
    
    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationContext;
    
    /**
     * Event raised when an {@code ApplicationContext} gets started.
     *
     * @author Mark Fisher
     * @author Juergen Hoeller
     * @since 2.5
     * @see ContextStoppedEvent
     */
    @SuppressWarnings("serial")
    public class ContextStartedEvent extends ApplicationContextEvent {
    
        /**
         * Create a new ContextStartedEvent.
         * @param source the {@code ApplicationContext} that has been started
         * (must not be {@code null})
         */
        public ContextStartedEvent(ApplicationContext source) {
            super(source);
        }
    
    }
    
    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationContext;
    
    /**
     * Event raised when an {@code ApplicationContext} gets closed.
     *
     * @author Juergen Hoeller
     * @since 12.08.2003
     * @see ContextRefreshedEvent
     */
    @SuppressWarnings("serial")
    public class ContextClosedEvent extends ApplicationContextEvent {
    
        /**
         * Creates a new ContextClosedEvent.
         * @param source the {@code ApplicationContext} that has been closed
         * (must not be {@code null})
         */
        public ContextClosedEvent(ApplicationContext source) {
            super(source);
        }
    
    }
    
    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationContext;
    
    /**
     * Event raised when an {@code ApplicationContext} gets stopped.
     *
     * @author Mark Fisher
     * @author Juergen Hoeller
     * @since 2.5
     * @see ContextStartedEvent
     */
    @SuppressWarnings("serial")
    public class ContextStoppedEvent extends ApplicationContextEvent {
    
        /**
         * Create a new ContextStoppedEvent.
         * @param source the {@code ApplicationContext} that has been stopped
         * (must not be {@code null})
         */
        public ContextStoppedEvent(ApplicationContext source) {
            super(source);
        }
    
    }
    
    



    在SpringContext进行refresh、start、stop、close时,分别会产生以上事件。

    Spring接口式监听事件实践

    我们刚好借容器内置事件进行接口式监听的实践。

    public class ApplicationListenerDemo {
       public static void main(String[] args) {
    
            GenericApplicationContext context = new GenericApplicationContext();
            context.register(ApplicationListenerDemo.class);
    
            context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
                @Override
                public void onApplicationEvent(ApplicationEvent event) {
                    System.out.println("Receive event : " + event);
                }
            });
    
            context.refresh();
            context.start();
            context.stop();
            context.close();
        }
    
    }
    
    Receive event : org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5910e440, started on Sun Jun 20 15:33:56 CST 2021]
    Receive event : org.springframework.context.event.ContextStartedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5910e440, started on Sun Jun 20 15:33:56 CST 2021]
    Receive event : org.springframework.context.event.ContextStoppedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5910e440, started on Sun Jun 20 15:33:56 CST 2021]
    Receive event : org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5910e440, started on Sun Jun 20 15:33:56 CST 2021]
    
    

    Spring注解式监听事件实践

    public class ApplicationListenerDemo {
       public static void main(String[] args) {
            //GenericApplicationContext context = new GenericApplicationContext();
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(ApplicationListenerDemo.class);
    
            context.refresh();
            context.start();
            context.stop();
            context.close();
        }
    
       @EventListener
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("@EventListener Receive event : " + event);
        }
    
    }
     
    
    @EventListener Receive event : org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 15:36:25 CST 2021]
    @EventListener Receive event : org.springframework.context.event.ContextStartedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 15:36:25 CST 2021]
    @EventListener Receive event : org.springframework.context.event.ContextStoppedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 15:36:25 CST 2021]
    @EventListener Receive event : org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 15:36:25 CST 2021]
    



    注解还有以下特性:

    • 异步
        @EventListener
        @Async
        public void onApplicationEventAsync(ApplicationEvent event) {
            System.out.println("@EventListener Receive event async: " + event);
        }
    
        @EnableAsync
        @Configuration
        public class ApplicationListenerDemo {
        }
    
    • 顺序
        @EventListener
        @Order(1)
        public void onApplicationEvent1(ApplicationEvent event) {
            System.out.println("@EventListener Receive event order 1");
        }
    
        @EventListener
        @Order(2)
        public void onApplicationEvent2(ApplicationEvent event) {
            System.out.println("@EventListener Receive event order 2");
        }
    
    • 支持多ApplicationEvent类型,无需接口约束
        @EventListener
        public void onApplicationEvent2(ContextStartedEvent event) {
            System.out.println("@EventListener Receive ContextStartedEvent order 2");
        }
    
    • 泛型
        @EventListener
        public void onApplicationEvent2(ContextStartedEvent<T> event) {
            System.out.println("@EventListener Receive ContextStartedEvent order 2");
        }
    

    Spring 4.2版本对于PayloadEvent的支持。

            if (event instanceof ApplicationEvent) {
                applicationEvent = (ApplicationEvent) event;
            }
            else {
                applicationEvent = new PayloadApplicationEvent<>(this, event);
                if (eventType == null) {
                    eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
                }
            }
    

    可以看到4.2以后不再强制要求Event是ApplicationEvent的子类,而是适配成了PayloadApplicationEvent对象。

    /*
     * Copyright 2002-2015 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context;
    
    import org.springframework.core.ResolvableType;
    import org.springframework.core.ResolvableTypeProvider;
    import org.springframework.util.Assert;
    
    /**
     * An {@link ApplicationEvent} that carries an arbitrary payload.
     *
     * <p>Mainly intended for internal use within the framework.
     *
     * @author Stephane Nicoll
     * @since 4.2
     * @param <T> the payload type of the event
     */
    @SuppressWarnings("serial")
    public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
    
        private final T payload;
    
    
        /**
         * Create a new PayloadApplicationEvent.
         * @param source the object on which the event initially occurred (never {@code null})
         * @param payload the payload object (never {@code null})
         */
        public PayloadApplicationEvent(Object source, T payload) {
            super(source);
            Assert.notNull(payload, "Payload must not be null");
            this.payload = payload;
        }
    
    
        @Override
        public ResolvableType getResolvableType() {
            return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getPayload()));
        }
    
        /**
         * Return the payload of the event.
         */
        public T getPayload() {
            return this.payload;
        }
    
    }
    
    

    Spring 事件发送器依赖注入和查找

    • ApplicationEventPublisher
      1.我们可以直接依赖注入ApplicationEventPublisher来进行事件发送
    public class ApplicationListenerDemo {
        @Autowired
        ApplicationEventPublisher applicationEventPublisher;
    
    
        @PostConstruct
        public void init() {
            applicationEventPublisher.publishEvent("ExtendSpringEvent");
        }
    }
    
    1. 我们可以通过Aware回调
    public class ApplicationListenerDemo implements ApplicationEventPublisherAware {
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            applicationEventPublisher.publishEvent("ExtendSpringEvent");
        }
    
        @PostConstruct
        public void init() {
            applicationEventPublisher.publishEvent("ExtendSpringEvent");
        }
    
    }
    
    
    1. 通过ApplicationContext容器间接引入
      在AbstractApplicationContext中有publishEvent方法,本身就是ApplicationEventPublisher接口的实现,委托applicationEventMulticaster进行事件发送,所以如果是ApplicationContext上下文中,是可以直接调publishEvent发送事件的。



    其实底层都是通过ApplicationEventMultiCaster来实现的,那我们来分析一下源码。
    首先看一下publishEvent实现,来看看ApplicationEventMultiCaster的作用。

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
            Assert.notNull(event, "Event must not be null");
    
            // Decorate event as an ApplicationEvent if necessary
            ApplicationEvent applicationEvent;
            if (event instanceof ApplicationEvent) {
                applicationEvent = (ApplicationEvent) event;
            }
            else {
                applicationEvent = new PayloadApplicationEvent<>(this, event);
                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 {
                getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
            }
    
            // Publish event via parent context as well...
            if (this.parent != null) {
                if (this.parent instanceof AbstractApplicationContext) {
                    ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
                }
                else {
                    this.parent.publishEvent(event);
                }
            }
        }
    
    

    payload这段讲过了,下面来到earlyApplicationEvents判断这里,这里是解决Spring 3.0版本的bug ,因为在BeanPostProcesser生命周期时,ApplicationEventMultiCaster还没有init,所以publishEvent会报错,这里用一组earlyEvents暂存。

    而初始化完成后的生命周期中,直接进入else逻辑,调用getApplicationEventMulticaster进行事件发送。

        ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
            if (this.applicationEventMulticaster == null) {
                throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
                        "call 'refresh' before multicasting events via the context: " + this);
            }
            return this.applicationEventMulticaster;
        }
    
    
    /*
     * Copyright 2002-2019 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.core.ResolvableType;
    import org.springframework.lang.Nullable;
    
    /**
     * Interface to be implemented by objects that can manage a number of
     * {@link ApplicationListener} objects and publish events to them.
     *
     * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically
     * a Spring {@link org.springframework.context.ApplicationContext}, can use an
     * {@code ApplicationEventMulticaster} as a delegate for actually publishing events.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Stephane Nicoll
     * @see ApplicationListener
     */
    public interface ApplicationEventMulticaster {
    
        /**
         * Add a listener to be notified of all events.
         * @param listener the listener to add
         */
        void addApplicationListener(ApplicationListener<?> listener);
    
        /**
         * Add a listener bean to be notified of all events.
         * @param listenerBeanName the name of the listener bean to add
         */
        void addApplicationListenerBean(String listenerBeanName);
    
        /**
         * Remove a listener from the notification list.
         * @param listener the listener to remove
         */
        void removeApplicationListener(ApplicationListener<?> listener);
    
        /**
         * Remove a listener bean from the notification list.
         * @param listenerBeanName the name of the listener bean to remove
         */
        void removeApplicationListenerBean(String listenerBeanName);
    
        /**
         * Remove all listeners registered with this multicaster.
         * <p>After a remove call, the multicaster will perform no action
         * on event notification until new listeners are registered.
         */
        void removeAllListeners();
    
        /**
         * Multicast the given application event to appropriate listeners.
         * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
         * if possible as it provides better support for generics-based events.
         * @param event the event to multicast
         */
        void multicastEvent(ApplicationEvent event);
    
        /**
         * Multicast the given application event to appropriate listeners.
         * <p>If the {@code eventType} is {@code null}, a default type is built
         * based on the {@code event} instance.
         * @param event the event to multicast
         * @param eventType the type of event (can be {@code null})
         * @since 4.2
         */
        void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
    
    }
    
    
    /*
     * Copyright 2002-2019 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.event;
    
    import java.util.concurrent.Executor;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.core.ResolvableType;
    import org.springframework.lang.Nullable;
    import org.springframework.util.ErrorHandler;
    
    /**
     * Simple implementation of the {@link ApplicationEventMulticaster} interface.
     *
     * <p>Multicasts all events to all registered listeners, leaving it up to
     * the listeners to ignore events that they are not interested in.
     * Listeners will usually perform corresponding {@code instanceof}
     * checks on the passed-in event object.
     *
     * <p>By default, all listeners are invoked in the calling thread.
     * This allows the danger of a rogue listener blocking the entire application,
     * but adds minimal overhead. Specify an alternative task executor to have
     * listeners executed in different threads, for example from a thread pool.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Stephane Nicoll
     * @see #setTaskExecutor
     */
    public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    
        @Nullable
        private Executor taskExecutor;
    
        @Nullable
        private ErrorHandler errorHandler;
    
    
        /**
         * Create a new SimpleApplicationEventMulticaster.
         */
        public SimpleApplicationEventMulticaster() {
        }
    
        /**
         * Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
         */
        public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
            setBeanFactory(beanFactory);
        }
    
    
        /**
         * Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
         * to invoke each listener with.
         * <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
         * executing all listeners synchronously in the calling thread.
         * <p>Consider specifying an asynchronous task executor here to not block the
         * caller until all listeners have been executed. However, note that asynchronous
         * execution will not participate in the caller's thread context (class loader,
         * transaction association) unless the TaskExecutor explicitly supports this.
         * @see org.springframework.core.task.SyncTaskExecutor
         * @see org.springframework.core.task.SimpleAsyncTaskExecutor
         */
        public void setTaskExecutor(@Nullable Executor taskExecutor) {
            this.taskExecutor = taskExecutor;
        }
    
        /**
         * Return the current task executor for this multicaster.
         */
        @Nullable
        protected Executor getTaskExecutor() {
            return this.taskExecutor;
        }
    
        /**
         * Set the {@link ErrorHandler} to invoke in case an exception is thrown
         * from a listener.
         * <p>Default is none, with a listener exception stopping the current
         * multicast and getting propagated to the publisher of the current event.
         * If a {@linkplain #setTaskExecutor task executor} is specified, each
         * individual listener exception will get propagated to the executor but
         * won't necessarily stop execution of other listeners.
         * <p>Consider setting an {@link ErrorHandler} implementation that catches
         * and logs exceptions (a la
         * {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
         * or an implementation that logs exceptions while nevertheless propagating them
         * (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
         * @since 4.1
         */
        public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
            this.errorHandler = errorHandler;
        }
    
        /**
         * Return the current error handler for this multicaster.
         * @since 4.1
         */
        @Nullable
        protected ErrorHandler getErrorHandler() {
            return this.errorHandler;
        }
    
    
        @Override
        public void multicastEvent(ApplicationEvent event) {
            multicastEvent(event, resolveDefaultEventType(event));
        }
    
        @Override
        public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
            ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
            Executor executor = getTaskExecutor();
            for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                if (executor != null) {
                    executor.execute(() -> invokeListener(listener, event));
                }
                else {
                    invokeListener(listener, event);
                }
            }
        }
    
        private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
            return ResolvableType.forInstance(event);
        }
    
        /**
         * Invoke the given listener with the given event.
         * @param listener the ApplicationListener to invoke
         * @param event the current event to propagate
         * @since 4.1
         */
        protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
            ErrorHandler errorHandler = getErrorHandler();
            if (errorHandler != null) {
                try {
                    doInvokeListener(listener, event);
                }
                catch (Throwable err) {
                    errorHandler.handleError(err);
                }
            }
            else {
                doInvokeListener(listener, event);
            }
        }
    
        @SuppressWarnings({"rawtypes", "unchecked"})
        private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
            try {
                listener.onApplicationEvent(event);
            }
            catch (ClassCastException ex) {
                String msg = ex.getMessage();
                if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                    // Possibly a lambda-defined listener which we could not resolve the generic event type for
                    // -> let's suppress the exception and just log a debug message.
                    Log logger = LogFactory.getLog(getClass());
                    if (logger.isTraceEnabled()) {
                        logger.trace("Non-matching event type for listener: " + listener, ex);
                    }
                }
                else {
                    throw ex;
                }
            }
        }
    
        private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
            // On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
            if (classCastMessage.startsWith(eventClass.getName())) {
                return true;
            }
            // On Java 11, the message starts with "class ..." a.k.a. Class.toString()
            if (classCastMessage.startsWith(eventClass.toString())) {
                return true;
            }
            // On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
            int moduleSeparatorIndex = classCastMessage.indexOf('/');
            if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
                return true;
            }
            // Assuming an unrelated class cast failure...
            return false;
        }
    
    }
    
    



    所以最终都是通过SimpleApplicationEventMulticaster#multicastEvent实现的,里面可以看到,如果没有指定线程池,将会同步调用消费者,所以Spring默认事件是主线程同步执行的。并且ErrorHandler的逻辑也在此可以看到。
    Spring全家桶中关于事件发送都是基于SimpleApplicationEventMulticaster实现的。

    ApplicationEventMultiCaster初始化

    那么这个SimpleApplicationEventMulticaster是什么时候初始化的呢?

        @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }
    



    refresh方法这个高频面试点不用多介绍了,我们直接进入initApplicationEventMulticaster方法实现。

        protected void initApplicationEventMulticaster() {
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
                this.applicationEventMulticaster =
                        beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
                if (logger.isTraceEnabled()) {
                    logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
                }
            }
            else {
                this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
                beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
                if (logger.isTraceEnabled()) {
                    logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                            "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
                }
            }
        }
    



    所以我们可以看到,Spring首先通过beanName查找依赖,如果找不到,new 一个SimpleApplicationEventMulticaster实现并且通过beanFactory手动register单例到容器里。
    那么我们就可以想到,如果我自己注册一个实现别名为applicationEventMulticaster,其实是可以跳过simple实现拓展着玩的,如下:

    @Configuration
    public class ApplicationListenerDemo   {
    
        @Autowired
        ApplicationEventPublisher applicationEventPublisher;
    
    
        @PostConstruct
        public void init() {
            applicationEventPublisher.publishEvent(new ExtendSpringEvent("ExtendSpringEvent"));
        }
    
        @Component(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
        static class MyApplicationEventMulticaster implements ApplicationEventMulticaster {
    
            @Override
            public void addApplicationListener(ApplicationListener<?> listener) {
                System.out.println("MyApplicationEventMulticaster addApplicationListener");
            }
    
            @Override
            public void addApplicationListenerBean(String listenerBeanName) {
    
            }
    
            @Override
            public void removeApplicationListener(ApplicationListener<?> listener) {
    
            }
    
            @Override
            public void removeApplicationListenerBean(String listenerBeanName) {
    
            }
    
            @Override
            public void removeAllListeners() {
    
            }
    
            @Override
            public void multicastEvent(ApplicationEvent event) {
            }
    
            @Override
            public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
                System.out.println("MyApplicationEventMulticaster multicastEvent: " + event);
            }
        }
    
    
        public static void main(String[] args) {
            //GenericApplicationContext context = new GenericApplicationContext();
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(ApplicationListenerDemo.class);
    
            context.refresh();
            context.start();
            context.stop();
            context.close();
        }
    
        static class ExtendSpringEvent extends ApplicationEvent {
    
            /**
             * Create a new {@code ApplicationEvent}.
             *
             * @param source the object on which the event initially occurred or with
             *               which the event is associated (never {@code null})
             */
            public ExtendSpringEvent(Object source) {
                super(source);
            }
        }
    
    }
    
    
    
    MyApplicationEventMulticaster multicastEvent: org.thinking.in.spring.ioc.lookup.event.ApplicationListenerDemo$ExtendSpringEvent[source=ExtendSpringEvent]
    MyApplicationEventMulticaster multicastEvent: org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 16:05:27 CST 2021]
    MyApplicationEventMulticaster multicastEvent: org.springframework.context.event.ContextStartedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 16:05:27 CST 2021]
    MyApplicationEventMulticaster multicastEvent: org.springframework.context.event.ContextStoppedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 16:05:27 CST 2021]
    MyApplicationEventMulticaster multicastEvent: org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c, started on Sun Jun 20 16:05:27 CST 2021]
    



    但是一般不需要拓展这个,因为还需要封装调用listener很多特性逻辑,你知道有这个点装逼就可以了,气质这块绝对不能颓。

    Spring 3.0 的bug是啥呢?回过头看refresh方法编排。

                // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    

    registerBeanPostProcessors的时候,很明显initApplicationEventMulticaster还没调到,那么就没有SimpleApplicationEventMulticaster这个单例,这时候事件肯定发不了报错了,所以弄出来一个earlyEvents暂存。

    ApplicationEventMulticaster模式上是有点像Observable的,所以说Spring事件整体架构上是借鉴了很多前人的思想,然后改良了实现。

    Multicaster异步和异常处理机制拓展

    • 异步处理

    异常处理机制是SimpleApplicationEventMulticaster独有的,ApplicationEventMulticaster接口中并没有taskExecutor对象,所以要通过类型判断强转来增加接口式监听的异步化。首先通过beanName拿到ApplicationEventMulticaster接口实例,然后把提前创建好的线程池赋值给强转后的SimpleMulticaster。

     ApplicationEventMulticaster applicationEventMulticaster = context.getBean(
                AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
                ApplicationEventMulticaster.class);
    
            ExecutorService executorService =
                new ThreadPoolExecutor(10, 10,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(),
                    new CustomizableThreadFactory("my-pool-"));
    
            if (applicationEventMulticaster instanceof SimpleApplicationEventMulticaster) {
                SimpleApplicationEventMulticaster simpleApplicationEventMulticaster
                    = (SimpleApplicationEventMulticaster)applicationEventMulticaster;
    
                simpleApplicationEventMulticaster.setTaskExecutor(executorService);
            }
    



    要注意的是这里线程池不能自动关闭,两种做法吧 ,监听容器Close事件来关闭,或者用jvm的shutdownhook。

            context.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
                @Override
                public void onApplicationEvent(ContextClosedEvent event) {
                    if (!executorService.isShutdown()) {
                        executorService.shutdown();
                    }
                }
            });
    
    • 异常处理机制
      同上,给一下异常处理实现。
           simpleApplicationEventMulticaster.setErrorHandler(new ErrorHandler() {
                    @Override
                    public void handleError(Throwable throwable) {
                        System.out.printf("事件消费异常:%s\n", throwable.getMessage());
                    }
                });
    

    结合起来的实践案例如下:

    public class ApplicationListenerDemo {
    
        public static void main(String[] args) {
            GenericApplicationContext context = new GenericApplicationContext();
    
            context.refresh();
    
            ApplicationEventMulticaster applicationEventMulticaster = context.getBean(
                AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
                ApplicationEventMulticaster.class);
    
            ExecutorService executorService =
                new ThreadPoolExecutor(10, 10,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(),
                    new CustomizableThreadFactory("my-pool-"));
    
            if (applicationEventMulticaster instanceof SimpleApplicationEventMulticaster) {
                SimpleApplicationEventMulticaster simpleApplicationEventMulticaster
                    = (SimpleApplicationEventMulticaster)applicationEventMulticaster;
    
                simpleApplicationEventMulticaster.setTaskExecutor(executorService);
                simpleApplicationEventMulticaster.setErrorHandler(new ErrorHandler() {
                    @Override
                    public void handleError(Throwable throwable) {
                        System.out.printf("事件消费异常:%s\n", throwable.getMessage());
                    }
                });
            }
    
            context.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
                @Override
                public void onApplicationEvent(ContextClosedEvent event) {
                    if (!executorService.isShutdown()) {
                        executorService.shutdown();
                    }
                }
            });
    
            context.addApplicationListener(new ApplicationListener<ExtendSpringEvent>() {
                @Override
                public void onApplicationEvent(ExtendSpringEvent event) {
                    System.err.printf("线程:%s 消费事件%s", Thread.currentThread().getName(), event);
                }
            });
    
            context.addApplicationListener(new ApplicationListener<ExtendSpringEvent>() {
                @Override
                public void onApplicationEvent(ExtendSpringEvent event) {
                    throw new RuntimeException("onApplicationEvent报错了");
                }
            });
    
            context.publishEvent(new ExtendSpringEvent("ExtendSpringEvent"));
    
            context.close();
        }
    
        static class ExtendSpringEvent extends ApplicationEvent {
    
            /**
             * Create a new {@code ApplicationEvent}.
             *
             * @param source the object on which the event initially occurred or with
             *               which the event is associated (never {@code null})
             */
            public ExtendSpringEvent(Object source) {
                super(source);
            }
        }
    
    }
    
    
    事件消费异常:onApplicationEvent报错了
    线程:my-pool-1 消费事件org.thinking.in.spring.ioc.lookup.event.ApplicationListenerDemo$ExtendSpringEvent[source=ExtendSpringEvent]
    Process finished with exit code 0
    
    

    总结

    事件驱动内存框架其实很多,但是现在Spring强大的地方在于生态,还有特性的迭代。

    像Google EventBus早期好用的地方也有Event可以是任何对象,早期的Spring Event还必须是ApplicationEvent子类,这个灵活性优势也没有了,其实工程研发中更推荐使用ApplicationEvent子类。

    EventBus现在比较受限的地方就是线程池,EventBus的事件分发机制有三种,其中异步分发模式是所有事件共用一个线程池,那么就有可能忙的Event把闲的Event饿死。

    在Spring Event-Driven的最佳实践方面,更推荐根据开发人员、项目背景来灵活运用,在了解Spring Event原理以后,做出合适的决策。

    相关文章

      网友评论

        本文标题:Spring Event-Driven Architecture

        本文链接:https://www.haomeiwen.com/subject/gucsyltx.html