當前位置:
首頁 > 知識 > 淺談Spring事件監聽

淺談Spring事件監聽

聲明:筆者以下所有的代碼和實驗都是基於Spring boot 的 2.0.0.RELEASE 版本。

另外筆者能力有限,文中但凡有不對或者用詞不當之處,望不吝指出。

在談Spring的事件監聽之前,讓我們先了解一下Spring容器,什麼是ApplicationContext ?

它是Spring的核心,Context我們通常解釋為上下文環境,但是理解成容器會更好些。

ApplicationContext則是應用的容器。

Spring把Bean(object)放在容器中,需要用就通過get方法取出來。

下面我們結合源碼注視和ApplicationContext的類圖來看看它到底提供給我們哪些能力

源碼:

/*

* Copyright 2002-2014 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

*

* http://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.beans.factory.HierarchicalBeanFactory;

import org.springframework.beans.factory.ListableBeanFactory;

import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

import org.springframework.core.env.EnvironmentCapable;

import org.springframework.core.io.support.ResourcePatternResolver;

import org.springframework.lang.Nullable;

/**

* Central interface to provide configuration for an application.

* This is read-only while the application is running, but may be

* reloaded if the implementation supports this.

*

* <p>An ApplicationContext provides:

* <ul>

* <li>Bean factory methods for accessing application components.

* Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.

* <li>The ability to load file resources in a generic fashion.

* Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.

* <li>The ability to publish events to registered listeners.

* Inherited from the {@link ApplicationEventPublisher} interface.

* <li>The ability to resolve messages, supporting internationalization.

* Inherited from the {@link MessageSource} interface.

* <li>Inheritance from a parent context. Definitions in a descendant context

* will always take priority. This means, for example, that a single parent

* context can be used by an entire web application, while each servlet has

* its own child context that is independent of that of any other servlet.

* </ul>

*

* <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}

* lifecycle capabilities, ApplicationContext implementations detect and invoke

* {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},

* {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.

*

* @author Rod Johnson

* @author Juergen Hoeller

* @see ConfigurableApplicationContext

* @see org.springframework.beans.factory.BeanFactory

* @see org.springframework.core.io.ResourceLoader

*/

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,

MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

/**

* Return the unique id of this application context.

* @return the unique id of the context, or {@code null} if none

*/

@Nullable

String getId();

/**

* Return a name for the deployed application that this context belongs to.

* @return a name for the deployed application, or the empty String by default

*/

String getApplicationName();

/**

* Return a friendly name for this context.

* @return a display name for this context (never {@code null})

*/

String getDisplayName();

/**

* Return the timestamp when this context was first loaded.

* @return the timestamp (ms) when this context was first loaded

*/

long getStartupDate();

/**

* Return the parent context, or {@code null} if there is no parent

* and this is the root of the context hierarchy.

* @return the parent context, or {@code null} if there is no parent

*/

@Nullable

ApplicationContext getParent();

/**

* Expose AutowireCapableBeanFactory functionality for this context.

* <p>This is not typically used by application code, except for the purpose of

* initializing bean instances that live outside of the application context,

* applying the Spring bean lifecycle (fully or partly) to them.

* <p>Alternatively, the internal BeanFactory exposed by the

* {@link ConfigurableApplicationContext} interface offers access to the

* {@link AutowireCapableBeanFactory} interface too. The present method mainly

* serves as a convenient, specific facility on the ApplicationContext interface.

* <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException

* after the application context has been closed.</b> In current Spring Framework

* versions, only refreshable application contexts behave that way; as of 4.2,

* all application context implementations will be required to comply.

* @return the AutowireCapableBeanFactory for this context

* @throws IllegalStateException if the context does not support the

* {@link AutowireCapableBeanFactory} interface, or does not hold an

* autowire-capable bean factory yet (e.g. if {@code refresh()} has

* never been called), or if the context has been closed already

* @see ConfigurableApplicationContext#refresh()

* @see ConfigurableApplicationContext#getBeanFactory()

*/

AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

類圖:

由源碼注釋:

此介面提供給Spring應用配置的能力,當應用啟動時,此介面的實現是只讀的,但是如果該實現支持,其內容也是可以重新載入的。

ApplicationContext大概提功能如下能力:

1.獲取應用組件的bean工廠方法,此能力繼承自org.springframework.beans.factory.ListableBeanFactory。

2.載入資源文件的能力,此能力繼承自org.springframework.core.io.ResourceLoader

3.發布事件到已註冊的監聽器,此能力繼承自ApplicationEventPublisher

4.提供國際化的消息訪問,此能力繼承自MessageSource

好對ApplicationContext有一定了解之後我們再來看看Spring提供的事件監聽。

為了實現事件監聽的能力Spring為我們提供了兩個頂層介面/抽象類

ApplcationEvent:是個抽象類,裡面只有一個構造函數和一個長整型的timestamp。我們自定義的Application event 需要繼承這個抽象類.

ApplicationListener:是一個介面,裡面只有一個方法onApplicationEvent ,每一個實現改介面的類都要自己實現這個方法。

Spring的事件監聽是基於標準的觀察者模式的,如果在ApplicationContext部署了一個實現了ApplicationListener的bean,那麼當一個ApplicationEvent發布到

ApplicationContext時,這個bean得到通知並作特定的處理。

從上面這段話我們很容易產生兩點思考:1.實現了ApplicationListener的bean如何部署到ApplicationContext 2.一個ApplicationEvent如何發布到ApplicationContext

下面我們就通過具體的代碼來看看這兩個問題

廢話少說,先看代碼!

先自定義一個MsgEvent,它本身提供一個print()方法:

package com.snow.event;

import org.springframework.context.ApplicationEvent;

/**

* Created by snowwolf-louis on 18/3/15.

*/

public class MsgEvent extends ApplicationEvent {

private String text;

public MsgEvent(Object source) {

super(source);

}

public MsgEvent(Object source, String text) {

super(source);

this.text = text;

}

public void print(){

System.out.println("print even content:" + this.text);

}

}

再自定義一個PringListener實現ApplicationListener:

package com.snow.listener;

import com.snow.event.MsgEvent;

import org.springframework.context.ApplicationListener;

/**

* Created by snowwolf-louis on 18/3/15.

*/

public class PrintListener implements ApplicationListener<MsgEvent> {

/**

* Handle an application event.

*

* @param event the event to respond to

*/

@Override

public void onApplicationEvent(MsgEvent event) {

System.out.print("調用MsgEvent的print方法輸出其內容:");

event.print();

}

}

現在自定義事件和監聽器都好了,我們就來看看第一個問題,監聽器如何部署到ApplicationContext,有四種方式可以實現,我們一個一個看:

1.應用啟動之前調用SpringApplication的addListeners方法將自定義的監聽器加入。

package com.snow;

import com.snow.event.MsgEvent;

import com.snow.listener.PrintListener;

import com.snow.publisher.SnowEventPublisher;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication

@RestController

public class SnowComponentApplication {

public static void main(String[] args) {

//創建SpringApplication

SpringApplication application = new SpringApplication(SnowComponentApplication.class);

//配置事件監聽

application.addListeners(new PrintListener());

//啟動應用並獲得上下文信息

ConfigurableApplicationContext context = application.run(args);

//發布事件

context.publishEvent(new MsgEvent(new Object(), "你好!"));

context.close();

}

}

運行結果:

2.監聽器部署到ApplicationContext,實際上就是將將監聽器交給Spring 容器管理,所以最簡單的方法只需在自定義的PrintListener上加上@Component註解就行了,代碼如下

package com.snow.listener;

import com.snow.event.MsgEvent;

import org.springframework.context.ApplicationListener;

import org.springframework.stereotype.Component;

/**

* Created by snowwolf-louis on 18/3/15.

*/

@Component

public class PrintListener implements ApplicationListener<MsgEvent> {

/**

* Handle an application event.

*

* @param event the event to respond to

*/

@Override

public void onApplicationEvent(MsgEvent event) {

System.out.print("調用MsgEvent的print方法輸出其內容:");

event.print();

}

}

啟動處的代碼注掉配置事件監聽一行,如下:

package com.snow;

import com.snow.event.MsgEvent;

import com.snow.listener.PrintListener;

import com.snow.publisher.SnowEventPublisher;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication

@RestController

public class SnowComponentApplication {

public static void main(String[] args) {

//創建SpringApplication

SpringApplication application = new SpringApplication(SnowComponentApplication.class);

//配置事件監聽

//application.addListeners(new PrintListener());

//啟動應用並獲得上下文信息

ConfigurableApplicationContext context = application.run(args);

//發布事件

context.publishEvent(new MsgEvent(new Object(), "你好!"));

context.close();

}

}

啟動運行,結果如下:

3.在配置文件中加入context.listener.classes: com.snow.listener.PrintListener

注釋掉PrintListener上的@Component註解

源碼分析:

Spring內置DelegatingApplicationListener會監聽ApplicationEnvironmentPreparedEvent事件(Environment已經準備好但是Context還沒有創建事件),

讀取Environment中的context.listener.classes屬性值(監聽器類全路徑,多個以逗號隔開)來創建ApplicationListener,詳情見如下源碼中我的注釋。

/*

* Copyright 2012-2017 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

*

* http://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.boot.context.config;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import org.springframework.beans.BeanUtils;

import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;

import org.springframework.context.ApplicationContextException;

import org.springframework.context.ApplicationEvent;

import org.springframework.context.ApplicationListener;

import org.springframework.context.event.SimpleApplicationEventMulticaster;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import org.springframework.core.env.ConfigurableEnvironment;

import org.springframework.util.Assert;

import org.springframework.util.ClassUtils;

import org.springframework.util.StringUtils;

/**

* {@link ApplicationListener} that delegates to other listeners that are specified under

* a {@literal context.listener.classes} environment property.

*

* @author Dave Syer

* @author Phillip Webb

*/

public class DelegatingApplicationListener

implements ApplicationListener<ApplicationEvent>, Ordered {

// NOTE: Similar to org.springframework.web.context.ContextLoader

private static final String PROPERTY_NAME = "context.listener.classes」;//配置文件中配置的配置

private int order = 0;

private SimpleApplicationEventMulticaster multicaster;

@Override

public void onApplicationEvent(ApplicationEvent event) {

if (event instanceof ApplicationEnvironmentPreparedEvent) {//監聽ApplicationEnvironmentPreparedEvent事件

List<ApplicationListener<ApplicationEvent>> delegates = getListeners(

((ApplicationEnvironmentPreparedEvent) event).getEnvironment());

if (delegates.isEmpty()) {

return;

}

this.multicaster = new SimpleApplicationEventMulticaster();

for (ApplicationListener<ApplicationEvent> listener : delegates) {

this.multicaster.addApplicationListener(listener);//將監聽事件加入spring容器中

}

}

if (this.multicaster != null) {

this.multicaster.multicastEvent(event);

}

}

@SuppressWarnings("unchecked")

private List<ApplicationListener<ApplicationEvent>> getListeners(

ConfigurableEnvironment environment) {

if (environment == null) {

return Collections.emptyList();

}

String classNames = environment.getProperty(PROPERTY_NAME);//獲取配置文件中配置的監聽器

List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<>();

if (StringUtils.hasLength(classNames)) {

for (String className : StringUtils.commaDelimitedListToSet(classNames)) {

try {

Class<?> clazz = ClassUtils.forName(className,

ClassUtils.getDefaultClassLoader());

Assert.isAssignable(ApplicationListener.class, clazz, "class ["

+ className + "] must implement ApplicationListener");

listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils

.instantiateClass(clazz));

}

catch (Exception ex) {

throw new ApplicationContextException(

"Failed to load context listener class [" + className + "]",

ex);

}

}

}

AnnotationAwareOrderComparator.sort(listeners);

return listeners;

}

public void setOrder(int order) {

this.order = order;

}

@Override

public int getOrder() {

return this.order;

}

}

運行結果:

4.使用@EventListener註解,先看代碼,建立一個普通的java類並交給spring容器,其中一個處理event的方法,加上該註解,刪掉配置文件中的配置。

package com.snow.handle;

import com.snow.event.MsgEvent;

import org.springframework.context.event.EventListener;

import org.springframework.stereotype.Component;

/**

* Created by snowwolf-louis on 18/3/17.

*/

@Component

public class MsgEventHandle {

@EventListener

public void handle(MsgEvent event){

event.print();

}

}

運行結果:

源碼分析:

我們首先看@EventListener註解的源碼,裡面有這樣一段注釋:

它指引我們去看EventListenerMethodProcessor類,這個類是application啟動時自動註冊執行的。該類的功能是掃描@EventListener註解並生成一個ApplicationListener實例。

其中有個這樣的方法:就是用來掃描容器中bean的方法上所有的@EventListener,循環創建ApplicationListener。

protected void processBean(

final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {

if (!this.nonAnnotatedClasses.contains(targetType)) {

Map<Method, EventListener> annotatedMethods = null;

try {

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();

for (Method method : annotatedMethods.keySet()) {

for (EventListenerFactory factory : factories) {

if (factory.supportsMethod(method)) {

Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));

ApplicationListener<?> applicationListener =

factory.createApplicationListener(beanName, targetType, methodToUse);

if (applicationListener instanceof ApplicationListenerMethodAdapter) {

((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);

}

context.addApplicationListener(applicationListener);

break;

}

}

}

if (logger.isDebugEnabled()) {

logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean "" +

beanName + "": " + annotatedMethods);

}

}

}

}

好以上四點就回答了我們開頭提出的第一個問題:實現了ApplicationListener的bean如何部署到ApplicationContext。接下來輪到第二個問題了,

一個ApplicationEvent如何發布到ApplicationContext。我們還是來看測試的主代碼:

package com.snow;

import com.snow.event.MsgEvent;

import com.snow.listener.PrintListener;

import com.snow.publisher.SnowEventPublisher;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication

@RestController

public class SnowComponentApplication {

public static void main(String[] args) {

//創建SpringApplication

SpringApplication application = new SpringApplication(SnowComponentApplication.class);

//配置事件監聽

//application.addListeners(new PrintListener());

//啟動應用並獲得上下文信息

ConfigurableApplicationContext context = application.run(args);

//發布事件

context.publishEvent(new MsgEvent(new Object(), "你好!"));

context.close();

}

}

上面的這段代碼可以看出ConfigurableApplicationContext具有發布事件的能力,而通過下面的類圖我們知道ConfigurableApplicationContext是

ApplicationContext的子介面,文章開頭對ApplicationContext的分析我們知道ApplicationContext具有發布事件的能力,這項能力是通過繼承

ApplicationEventPublisher獲得的。

通過以上分析,我們不難發現,只要我們在一個普通的java bean注入ApplicationContext的實例,那麼這個bean就獲得了發布事件的能力。

那麼怎樣才能在一個普通的bean中注入ApplicationContext的實例呢?看ApplicationContext的源碼,源碼中有這一段注釋:

這段注釋大概的意思是ApplicationContext的實例可以探測和喚起AppliationContextAware ,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware等,

我們順勢看下AppliationContextAware的代碼,如下:

/*

* 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

*

* http://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.beans.BeansException;

import org.springframework.beans.factory.Aware;

/**

* Interface to be implemented by any object that wishes to be notified

* of the {@link ApplicationContext} that it runs in.

*

* <p>Implementing this interface makes sense for example when an object

* requires access to a set of collaborating beans. Note that configuration

* via bean references is preferable to implementing this interface just

* for bean lookup purposes.

*

* <p>This interface can also be implemented if an object needs access to file

* resources, i.e. wants to call {@code getResource}, wants to publish

* an application event, or requires access to the MessageSource. However,

* it is preferable to implement the more specific {@link ResourceLoaderAware},

* {@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface

* in such a specific scenario.

*

* <p>Note that file resource dependencies can also be exposed as bean properties

* of type {@link org.springframework.core.io.Resource}, populated via Strings

* with automatic type conversion by the bean factory. This removes the need

* for implementing any callback interface just for the purpose of accessing

* a specific file resource.

*

* <p>{@link org.springframework.context.support.ApplicationObjectSupport} is a

* convenience base class for application objects, implementing this interface.

*

* <p>For a list of all bean lifecycle methods, see the

* {@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}.

*

* @author Rod Johnson

* @author Juergen Hoeller

* @author Chris Beams

* @see ResourceLoaderAware

* @see ApplicationEventPublisherAware

* @see MessageSourceAware

* @see org.springframework.context.support.ApplicationObjectSupport

* @see org.springframework.beans.factory.BeanFactoryAware

*/

public interface ApplicationContextAware extends Aware {

/**

* Set the ApplicationContext that this object runs in.

* Normally this call will be used to initialize the object.

* <p>Invoked after population of normal bean properties but before an init callback such

* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}

* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},

* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and

* {@link MessageSourceAware}, if applicable.

* @param applicationContext the ApplicationContext object to be used by this object

* @throws ApplicationContextException in case of context initialization errors

* @throws BeansException if thrown by application context methods

* @see org.springframework.beans.factory.BeanInitializationException

*/

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

通過ApplicationContextAware的源碼我們可以看出其有一個setApplicationContext 方法可以將ApplicationContext實例注入,下面我們

寫一個java類去實現 ApplicationContextAware看看。代碼如下:

package com.snow;

import com.snow.event.MsgEvent;

import com.snow.listener.PrintListener;

import com.snow.publisher.SnowApplcationContextAware;

import com.snow.publisher.SnowEventPublisher;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication

@RestController

public class SnowComponentApplication {

public static void main(String[] args) {

//創建SpringApplication

SpringApplication application = new SpringApplication(SnowComponentApplication.class);

//配置事件監聽

//application.addListeners(new PrintListener());

//啟動應用並獲得上下文信息

ConfigurableApplicationContext context = application.run(args);

//發布事件

//context.publishEvent(new MsgEvent(new Object(), "你好!"));

//context.close();

}

@Autowired

private SnowApplcationContextAware applcationContextAware;

@RequestMapping(value = "/hello")

public String sayHello(){

applcationContextAware.publish(new MsgEvent(new Object(),"有人訪問我,我得跟他們說:hello"));

return "hello";

}

}

運行代碼,打開瀏覽器訪問http:localhost:8080/hello,結果如下:

控制台信息如下:

通過這種方式事件的確發布了。

--難道這樣就完了嗎?

--嗯,別人的博客也許這樣就完了,但是雪夜蒼狼的不會。

我們注意到ApplicationContext的事件發布能力是繼承自ApplicationEventPublisher,並且ApplicationContextAware中有這樣一段注釋:

這段注釋可以看出,如果僅僅想獲取發布事件的能力,只需要實現ApplicationEventPublisherAware就行了。

照著這樣的思路代碼如下:定義一個事件發布器

package com.snow.publisher;

import org.springframework.context.ApplicationEvent;

import org.springframework.context.ApplicationEventPublisher;

import org.springframework.context.ApplicationEventPublisherAware;

import org.springframework.stereotype.Component;

/**

* Created by snowwolf-louis on 18/3/17.

*/

@Component

public class SnowEventPublisher implements ApplicationEventPublisherAware {

private ApplicationEventPublisher publisher;

@Override

public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

this.publisher = applicationEventPublisher;

}

public void publish(ApplicationEvent event){

publisher.publishEvent(event);

}

}

主測試代碼改成這樣:

package com.snow;

import com.snow.event.MsgEvent;

import com.snow.listener.PrintListener;

import com.snow.publisher.SnowApplcationContextAware;

import com.snow.publisher.SnowEventPublisher;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication

@RestController

public class SnowComponentApplication {

public static void main(String[] args) {

//創建SpringApplication

SpringApplication application = new SpringApplication(SnowComponentApplication.class);

//配置事件監聽

//application.addListeners(new PrintListener());

//啟動應用並獲得上下文信息

ConfigurableApplicationContext context = application.run(args);

//發布事件

//context.publishEvent(new MsgEvent(new Object(), "你好!"));

//context.close();

}

// @Autowired

// private SnowApplcationContextAware applcationContextAware;

@Autowired

private SnowEventPublisher snowEventPublisher;

@RequestMapping(value = "/hello")

public String sayHello(){

snowEventPublisher.publish(new MsgEvent(new Object(),"有人訪問我,我得跟他們說:hello"));

return "hello";

}

}

運行代碼,打開瀏覽器訪問http:localhost:8080/hello,結果如下:

淺談Spring事件監聽

控制台依然列印了如下信息,證明我們的猜想沒錯。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

求助:threejs+qml+json模型載入失敗
SpringBoot:SpringDataRedis緩存改造

TAG:程序員小新人學習 |