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);
- }
- }
- }
转自:http://wujiu.iteye.com/blog/2274871