Spring 应用上下文支持基于事件的Bean间通信。在基于事件的通信模式中,事件的发送者不需要关系,事件的监听者。这样可以使消息的发送者和监听者进行解耦。
在Spring中所有事件类必须继承自ApplicationEvent,这样任何bean都可以调用事件发布者的publishEvent()方法,发布一个事件。
public class MyEvent extends ApplicationEvent { /** */ private static final long serialVersionUID = 1L; /** * @param source */ public MyEvent(Object source) { super(source); } }
@Component("eventPublisher") public class EventPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher applicationEventPublisher; public void ckeckout(){ applicationEventPublisher.publishEvent(new MyEvent(this)); } /** * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher) */ @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher=applicationEventPublisher; } }
@Component public class MyListener implements ApplicationListener<MyEvent> { /** * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ @Override public void onApplicationEvent(MyEvent event) { System.out.println(Thread.currentThread().getName()+";"+event.getTimestamp()); } }
public class Test { /** * * @param args * @author zhangwei<wei.zw@corp.netease.com> */ public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); EventPublisher cashier = (EventPublisher) context.getBean("eventPublisher"); for(int i=0;i<20;i++) { cashier.ckeckout(); } } }
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="5" /> <property name="keepAliveSeconds" value="30000" /> <property name="maxPoolSize" value="1000" /> <property name="queueCapacity" value="200" /> </bean> <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster"> <property name="taskExecutor" ref="taskExecutor" /> </bean>
taskExecutor-1;1454033201241 taskExecutor-2;1454033201242 taskExecutor-3;1454033201242 taskExecutor-4;1454033201242 taskExecutor-5;1454033201243 taskExecutor-1;1454033201243 taskExecutor-3;1454033201243 taskExecutor-3;1454033201243 taskExecutor-2;1454033201243 taskExecutor-5;1454033201243 taskExecutor-1;1454033201243 taskExecutor-4;1454033201243 taskExecutor-3;1454033201243 taskExecutor-2;1454033201244 taskExecutor-5;1454033201244 taskExecutor-5;1454033201244 taskExecutor-4;1454033201244 taskExecutor-3;1454033201244 taskExecutor-2;1454033201244 taskExecutor-5;1454033201244
通过上面的一个示例,实现了异步的基于事件通信。
在AbstractApplicationContext中发布事件的实现如下,首先获取applicationEventMulticaster,通过其发布事件。
/** * Publish the given event to all listeners. * <p>Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be application-specific or a * standard framework event) */ public void publishEvent(ApplicationEvent event) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } getApplicationEventMulticaster().multicastEvent(event); if (this.parent != null) { this.parent.publishEvent(event); } }
在看看ApplicaitonEventMulticaster的初始化逻辑,如果在有配置过applicationEventMulticaster则直接使用,否则创建一个;注意,配置是ID必须是applicationEventMulticaster
/** * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ 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.isDebugEnabled()) { logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isDebugEnabled()) { logger.debug("Unable to locate ApplicationEventMulticaster with name '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "': using default [" + this.applicationEventMulticaster + "]"); } } }
再看看ApplicationEventMulticaster中又是如何发布事件的。如果有配置线程池,则异步处理,否则同步处理。
public void multicastEvent(final ApplicationEvent event) { for (final ApplicationListener listener : getApplicationListeners(event)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @SuppressWarnings("unchecked") public void run() { listener.onApplicationEvent(event); } }); } else { listener.onApplicationEvent(event); } } }