详解Spring中的Event事件处理机制和原理

本文内容纲要:

- Spring里的5种标准事件

- 好处

- 示例

- 自定义事件类

- 事件监听类

- 事件发布类

- 测试类

- 结果

- Spring Event事件通知原理

- 异步响应Event

- 自定义SimpleApplicationEventMulticaster

- 添加AsyncTaskConfig配置类

- @Async原理

- 总结

我们都知道 Spring 的核心是 ApplicationContext,它负责管理 bean 的完整生命周期。当spring加载 bean 时,ApplicationContext 会发布某些类型的事件。例如,当上下文启动时,会发布ContextStartedEvent,当上下文停止时,会发布ContextStoppedEvent。

Spring里的5种标准事件

上下文更新事件(ContextRefreshedEvent)在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发
上下文开始事件(ContextStartedEvent)当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件
上下文停止事件(ContextStoppedEvent)当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件
上下文关闭事件(ContextClosedEvent)当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁
请求处理事件(RequestHandledEvent)在Web应用中,当一个http请求(request)结束触发该事件

如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

注意:由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。

好处

Spring的事件通知机制是一项很有用的功能,使用事件机制我们可以将相互耦合的代码解耦,从而方便功能的修改与添加。

示例

除了上面介绍的5个spring已经帮我们实现的事件,我们还可以实现自定义事件。

举个例子,假设有一个添加评论的方法,在评论添加成功之后需要进行修改redis缓存、给用户添加积分等等操作。当然可以在添加评论的代码后面假设这些操作,但是这样的代码违反了设计模式的多项原则:单一职责原则、迪米特法则、开闭原则。一句话说就是耦合性太大了,比如将来评论添加成功之后还需要有另外一个操作,这时候我们就需要去修改我们的添加评论代码了。

自定义事件类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

* 自定义的事件类

*/

@Getter

@Setter

publicclassCustomEventextendsApplicationEvent{

 

    privateStringmessage;

 

    /**

     * Create a new ApplicationEvent.

     *

     * @param source the object on which the event initially occurred (never {@code null})

     */

    publicCustomEvent(Objectsource,Stringmessage){

        super(source);

        this.message=message;

    }

 

}

事件监听类

1

2

3

4

5

6

7

8

9

10

11

/**

* 事件监听类

*/

@Component

@Slf4j

publicclassCustomEventListenerimplementsApplicationListener<CustomEvent>{

    @Override

    publicvoidonApplicationEvent(CustomEvent event){

        log.info("get msg:{}",event.getMessage());

    }

}

事件发布类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/**

* 事件发布类

*/

@Component

publicclassCustomEventPublish{

 

    @Autowired

    privateApplicationEventPublisher eventPublisher;

 

    publicvoidpublish(Stringmessage){

        CustomEvent event=newCustomEvent(this,message);

        eventPublisher.publishEvent(event);

    }

 

}

测试类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

/**

* 测试类

*/

@RunWith(SpringRunner.class)

@SpringBootTest

publicclassSpringeventApplicationTests{

 

    @Autowired

    privateCustomEventPublish eventPublish;

 

    @Test

     publicvoidtest(){

        eventPublish.publish("888888888888888888");

    }

 

}

 

结果

1

INFO15108---[           main]c.e.s.e.listener.CustomEventListener     :get msg:888888888888888888

Spring Event事件通知原理

首先我们跟踪publishEvent方法,这个方法在AbstractApplicationContext类中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

protectedvoidpublishEvent(Objectevent,@Nullable ResolvableType eventType){

    Assert.notNull(event,"Event must not be null");

 

    // Decorate event as an ApplicationEvent if necessary

    ApplicationEvent applicationEvent;

    if(event instanceofApplicationEvent){

        // 如果event是ApplicationEvent对象

        applicationEvent=(ApplicationEvent)event;

    }

    else{

        // 如果event不是ApplicationEvent对象,则将其包装成PayloadApplicationEvent事件,并获取对应的事件类型

        applicationEvent=newPayloadApplicationEvent<>(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{

        // 获取ApplicationEventMulticaster,调用`multicastEvent`方法广播事件

        getApplicationEventMulticaster().multicastEvent(applicationEvent,eventType);

    }

 

    // 如果当前命名空间还有父亲节点,也需要给父亲推送该消息

    // Publish event via parent context as well...

    if(this.parent!=null){

        if(this.parent instanceofAbstractApplicationContext){

            ((AbstractApplicationContext)this.parent).publishEvent(event,eventType);

        }

        else{

            this.parent.publishEvent(event);

        }

    }

}

 

// 获取ApplicationEventMulticaster

ApplicationEventMulticaster getApplicationEventMulticaster()throwsIllegalStateException{

    if(this.applicationEventMulticaster==null){

        thrownewIllegalStateException("ApplicationEventMulticaster not initialized - "+

                "call 'refresh' before multicasting events via the context: "+this);

    }

    returnthis.applicationEventMulticaster;

}

经过上面的分析,我们看到事件是通过applicationEventMulticaster来广播出去的。

applicationEventMulticaster在Spring的启动过程中被建立,在Spring的启动过程中,在核心方法refresh中建立applicationEventMulticaster:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// Initialize message source for this context.

initMessageSource();

 

// Initialize event multicaster for this context.

// 在Spring容器中初始化事件广播器,事件广播器用于事件的发布

initApplicationEventMulticaster();

 

// Initialize other special beans in specific context subclasses.

onRefresh();

 

// Check for listener beans and register them.

// 把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加的事件广播器中。

registerListeners();

 

// Instantiate all remaining (non-lazy-init) singletons.

finishBeanFactoryInitialization(beanFactory);

 

// Last step: publish corresponding event.

finishRefresh();

关注initApplicationEventMulticaster和registerListeners方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 初始化事件广播器

protectedvoidinitApplicationEventMulticaster(){

    ConfigurableListableBeanFactory beanFactory=getBeanFactory();

    // 如果用户手动新建了一个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件广播器

    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{

        // 否则新建一个SimpleApplicationEventMulticaster作为默认的事件广播器

        this.applicationEventMulticaster=newSimpleApplicationEventMulticaster(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()+"]");

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// 注册监听器

protectedvoidregisterListeners(){

    // Register statically specified listeners first.

    // 把提前存储好的监听器添加到监听器容器中

    for(ApplicationListener<?>listener:getApplicationListeners()){

        getApplicationEventMulticaster().addApplicationListener(listener);

    }

 

    // Do not initialize FactoryBeans here: We need to leave all regular beans

    // uninitialized to let post-processors apply to them!

    // 获取类型是ApplicationListener的beanName集合,此处不会去实例化bean

    String[]listenerBeanNames=getBeanNamesForType(ApplicationListener.class,true,false);

    for(StringlistenerBeanName:listenerBeanNames){

        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

    }

 

    // Publish early application events now that we finally have a multicaster...

    Set<ApplicationEvent>earlyEventsToProcess=this.earlyApplicationEvents;

    this.earlyApplicationEvents=null;

    // 如果存在earlyEventsToProcess,提前处理这些事件

    if(earlyEventsToProcess!=null){

        for(ApplicationEvent earlyEvent:earlyEventsToProcess){

            getApplicationEventMulticaster().multicastEvent(earlyEvent);

        }

    }

}

经过前面的分析,我们知道了事件广播器applicationEventMulticaster如何被构建,下面我们分析事件的广播过程。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

@Override

publicvoidmulticastEvent(finalApplicationEvent event,@Nullable ResolvableType eventType){

    ResolvableType type=(eventType!=null?eventType:resolveDefaultEventType(event));

    // 根据event类型获取适合的监听器

    for(finalApplicationListener<?>listener:getApplicationListeners(event,type)){

        // 获取SimpleApplicationEventMulticaster中的线程执行器,如果存在线程执行器则在新线程中异步执行,否则直接同步执行监听器中的方法

        Executor executor=getTaskExecutor();

        if(executor!=null){

            executor.execute(()->invokeListener(listener,event));

        }

        else{

            invokeListener(listener,event);

        }

    }

}

 

protectedvoidinvokeListener(ApplicationListener<?>listener,ApplicationEvent event){

    // 如果存在ErrorHandler,调用监听器方法如果抛出异常则调用ErrorHandler来处理异常。否则直接调用监听器方法

    ErrorHandler errorHandler=getErrorHandler();

    if(errorHandler!=null){

        try{

            doInvokeListener(listener,event);

        }

        catch(Throwable err){

            errorHandler.handleError(err);

        }

    }

    else{

        doInvokeListener(listener,event);

    }

}

经过上面的分析,我们知道了Spring如何发送并响应事件。下面我们来分析如何使Spring能够异步响应事件。

异步响应Event

默认情况下,Spring是同步执行Event的响应方法的。如果响应方法的执行时间很长会阻塞发送事件的方法,因此很多场景下,我们需要让事件的响应异步化。

自定义SimpleApplicationEventMulticaster

通过前面的代码分析,我们发现如果SimpleApplicationEventMulticaster中的taskExecutor如果不为null,将在taskExecutor中异步执行响应程序。

applicationEventMulticaster的新建在initApplicationEventMulticaster方法中,默认情况下它会新建一个SimpleApplicationEventMulticaster,其中的taskExecutor为null。因此想要taskExecutor不为null,我们可以自己手动创建一个SimpleApplicationEventMulticaster然后设置一个taskExecutor。

添加AsyncTaskConfig配置类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Configuration

publicclassAsyncTaskConfig{

    @Bean

    publicSimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){

        returnnewSimpleAsyncTaskExecutor();

    }

 

    @Bean

    publicSimpleApplicationEventMulticaster applicationEventMulticaster(){

        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster=newSimpleApplicationEventMulticaster();

        simpleApplicationEventMulticaster.setTaskExecutor(simpleAsyncTaskExecutor());

        returnsimpleApplicationEventMulticaster;

    }

}

此时再次执行程序,执行结果如下:

1

[TaskExecutor-13]c.e.s.e.listener.CustomEventListener     :get msg:888888888888888888

可以看到这边是在新线程TaskExecutor-13里执行的,而不是像上面那样在main主线程里执行的。

@Async原理

@Async注解可以将方法异步化,下面我们来看看它的原理是什么。

我们在Config类中添加了@EnableAsync注释。@EnableAsync注释引入AsyncConfigurationSelector类,AsyncConfigurationSelector类导入ProxyAsyncConfiguration类,ProxyAsyncConfiguration类新建过程中会新建AsyncAnnotationBeanPostProcessor。

AsyncAnnotationBeanPostProcessor类继承了BeanPostProcessor,当每个Bean新建完成后会调用AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

@Override

publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){

    if(this.advisor==null||bean instanceofAopInfrastructureBean){

        // Ignore AOP infrastructure such as scoped proxies.

        returnbean;

    }

 

    if(bean instanceofAdvised){

        Advised advised=(Advised)bean;

        if(!advised.isFrozen()&&isEligible(AopUtils.getTargetClass(bean))){

            // Add our local Advisor to the existing proxy's Advisor chain...

            if(this.beforeExistingAdvisors){

                advised.addAdvisor(0,this.advisor);

            }

            else{

                advised.addAdvisor(this.advisor);

            }

            returnbean;

        }

    }

 

    if(isEligible(bean,beanName)){

        ProxyFactory proxyFactory=prepareProxyFactory(bean,beanName);

        if(!proxyFactory.isProxyTargetClass()){

            evaluateProxyInterfaces(bean.getClass(),proxyFactory);

        }

        proxyFactory.addAdvisor(this.advisor);

        customizeProxyFactory(proxyFactory);

        returnproxyFactory.getProxy(getProxyClassLoader());

    }

 

    // No proxy needed.

    returnbean;

}

postProcessAfterInitialization方法判断bean是否符合要求(方法上是否加了@Async注释),如果符合要求则对bean加上代理,代理类为AnnotationAsyncExecutionInterceptor。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

@Override

@Nullable

publicObjectinvoke(finalMethodInvocation invocation)throwsThrowable{

    Class<?>targetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null);

    Method specificMethod=ClassUtils.getMostSpecificMethod(invocation.getMethod(),targetClass);

    finalMethod userDeclaredMethod=BridgeMethodResolver.findBridgedMethod(specificMethod);

 

    // 获取executor

    AsyncTaskExecutor executor=determineAsyncExecutor(userDeclaredMethod);

    if(executor==null){

        thrownewIllegalStateException(

                "No executor specified and no default executor set on AsyncExecutionInterceptor either");

    }

 

    // 将我们真正的方法包装成一个`Callable`任务

    Callable<Object>task=()->{

        try{

            Objectresult=invocation.proceed();

            if(result instanceofFuture){

                return((Future<?>)result).get();

            }

        }

        catch(ExecutionException ex){

            handleError(ex.getCause(),userDeclaredMethod,invocation.getArguments());

        }

        catch(Throwable ex){

            handleError(ex,userDeclaredMethod,invocation.getArguments());

        }

        returnnull;

    };

    

    // 将任务提交到`executor`中执行

    returndoSubmit(task,executor,invocation.getMethod().getReturnType());

}

调用我们的方法时首先调用AnnotationAsyncExecutionInterceptor的invoke方法,invoke方法将我们真正的方法包装成一个Callable任务,将这个任务提交到executor中执行。由此达到了将我们的方法异步化的目的。

总结

Spring的事件机制是一套相当灵活的机制,使用它可以简便地将我们的代码解耦从而优化我们的代码。经过前面的分析我们了解了其中的运行原理,这有助于我们更好地使用这套机制。

本文内容总结:Spring里的5种标准事件,好处,示例,自定义事件类,事件监听类,事件发布类,测试类,结果,Spring Event事件通知原理,异步响应Event,自定义SimpleApplicationEventMulticaster,添加AsyncTaskConfig配置类,@Async原理,总结,

原文链接:https://www.cnblogs.com/shamo89/p/15715091.html

以上是 详解Spring中的Event事件处理机制和原理 的全部内容, 来源链接: utcz.com/z/296515.html

回到顶部