Event handling in the ApplicationContext is provided through the ApplicationEvent class and ApplicationListener interface. If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified. Essentially, this is the standard Observer design pattern. Spring 内置提供的标准事件包括:
ContextRefreshedEvent
Published when the ApplicationContext is initialized or refreshed, for example, using the refresh() method on the ConfigurableApplicationContext interface. "Initialized" here means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such "hot" refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.
ContextStartedEvent
Published when the ApplicationContext is started, using the start() method on the ConfigurableApplicationContext interface. "Started" here means that all Lifecycle beans receive an explicit start signal. Typically this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart , for example, components that have not already started on initialization.
ContextStoppedEvent
Published when the ApplicationContext is stopped, using the stop() method on the ConfigurableApplicationContext interface. "Stopped" here means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call.
ContextClosedEvent
Published when the ApplicationContext is closed, using the close() method on the ConfigurableApplicationContext interface. "Closed" here means that all singleton beans are destroyed. A closed context reaches its end of life; it cannot be refreshed or restarted.
RequestHandledEvent
A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications using Spring’s DispatcherServlet.
创建自己的事件只需要继承ApplicationEvent类,如下所示:
public class BlackListEvent extends ApplicationEvent { private final String address; private final String test; public BlackListEvent(Object source, String address, String test) { super(source); this.address = address; this.test = test; } // accessor and other methods... }
如果我们要发布上述事件,我们需要调用 ApplicationEventPublisher接口的publishEvent()方法,通常我们可以创建一个类实现ApplicationEventPublisherAware接口,并将它注册为Bean.示例如下:
public class EmailService implements ApplicationEventPublisherAware { private ListblackList; private ApplicationEventPublisher publisher; public void setBlackList(List blackList) { this.blackList = blackList; } public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } public void sendEmail(String address, String text) { if (blackList.contains(address)) { BlackListEvent event = new BlackListEvent(this, address, text); publisher.publishEvent(event); return; } // send email... } }
在配置时,Spring容器会探测到EmailService 实现了ApplicationEventPublisherAware接口并自动的调用setApplicationEventPublisher()方法。实际上这个方法的参数就是Spring容器本身;通过ApplicationEventPublisher 接口与我们便可以与应用程序上下文进行交互。
如果要消费这个事件,则需要编写一个类实现ApplicationListener 接口并将之注册为Spring 的bean.以下示例阐述了这一点。
public class BlackListNotifier implements ApplicationListener{ private String notificationAddress; public void setNotificationAddress(String notificationAddress) { this.notificationAddress = notificationAddress; } public void onApplicationEvent(BlackListEvent event) { // notify appropriate parties via notificationAddress... } }
Notice that ApplicationListener is generically parameterized with the type of your custom event, BlackListEvent. This means that the onApplicationEvent() method can remain type-safe, avoiding any need for downcasting. You may register as many event listeners as you wish, 需要注意的一点是所有事件监听都是同步的接收事件.这就表示 publishEvent() 方法被阻塞直到所有监听器完成事件处理. 这种同步和单线程方式的一个优点是,当监听器接收到事件时,如果发现事务上下文可用,那么它将在发布服务者的事务上下文中操作。如果我们想要定制事件发布的一些策略,可了解Spring的ApplicationEventMulticaster接口。