• Spring 基于事件的通信


    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);
    			}
    		}
    	}
  • 相关阅读:
    把旧系统迁移到.Net Core 2.0 日记 (18) --JWT 认证(Json Web Token)
    把旧系统迁移到.Net Core 2.0 日记 (17) --多租户和SoftDelete
    swagger访问api, TypeError: Failed to fetch
    nop 4.1 Widget 探究- 视图组件
    Nop 4.1版本已经迁移到.net core2.1版本
    link标签和css引入方式
    script标签
    MIME 类型
    bae64编码
    chrome调试技巧和插件介绍
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8797741.html
Copyright © 2020-2023  润新知