• Spring Session event事件分析


    1. org.apache.catalina.session.StandardSession 这是servlet-api jar包中的一个类。是session接口的标准实现。当session创建的时候会通知监听者,同理,session销毁的时候也会产生事件,代码如下:

     /**
         * Inform the listeners about the new session.
         *
         */
        public void tellNew() {
    
            // Notify interested session event listeners
            fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
    
            // Notify interested application event listeners
            Context context = (Context) manager.getContainer();
            Object listeners[] = context.getApplicationLifecycleListeners();
            if (listeners != null) {
                HttpSessionEvent event =
                    new HttpSessionEvent(getSession());
                for (int i = 0; i < listeners.length; i++) {
                    if (!(listeners[i] instanceof HttpSessionListener))
                        continue;
                    HttpSessionListener listener =
                        (HttpSessionListener) listeners[i];
                    try {
                        context.fireContainerEvent("beforeSessionCreated",
                                listener);
                        listener.sessionCreated(event);
                        context.fireContainerEvent("afterSessionCreated", listener);
                    } catch (Throwable t) {
                        ExceptionUtils.handleThrowable(t);
                        try {
                            context.fireContainerEvent("afterSessionCreated",
                                    listener);
                        } catch (Exception e) {
                            // Ignore
                        }
                        manager.getContainer().getLogger().error
                            (sm.getString("standardSession.sessionEvent"), t);
                    }
                }
            }
    
        }
    

      

    2. 上面标红的session event监听器哪里来的呢?答案是web.xml。我们需要在web.xml中添加如下配置:

    <listener>  
            <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>  
        </listener>  

    3. 接着,在HttpSessionEventPublisher中,从HttpSessionEvent中获取session,再从session中获取ServletContext,进而获取spring 容器(ApplicationContext),然后往容器发送event,代码如下:

    /**
    	 * Handles the HttpSessionEvent by publishing a {@link HttpSessionCreatedEvent} to the
    	 * application appContext.
    	 *
    	 * @param event HttpSessionEvent passed in by the container
    	 */
    	public void sessionCreated(HttpSessionEvent event) {
    		HttpSessionCreatedEvent e = new HttpSessionCreatedEvent(event.getSession());
    		Log log = LogFactory.getLog(LOGGER_NAME);
    
    		if (log.isDebugEnabled()) {
    			log.debug("Publishing event: " + e);
    		}
    
    		getContext(event.getSession().getServletContext()).publishEvent(e);
    	}
    

     

    AbstractApplicationContext.java: 事件发布

     

    protected void publishEvent(Object event, ResolvableType eventType) {
    		Assert.notNull(event, "Event must not be null");
    		if (logger.isTraceEnabled()) {
    			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    		}
    
    		// Decorate event as an ApplicationEvent if necessary
    		ApplicationEvent applicationEvent;
    		if (event instanceof ApplicationEvent) {
    			applicationEvent = (ApplicationEvent) event;
    		}
    		else {
    			applicationEvent = new PayloadApplicationEvent<Object>(this, event);
    			if (eventType == null) {
    				eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
    			}
    		}
    
    		// Multicast right now if possible - or lazily once the multicaster is initialized
    		if (this.earlyApplicationEvents != null) {
    			this.earlyApplicationEvents.add(applicationEvent);
    		}
    		else {
    			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); // 通过事件广播器广播事件
    		}
    
    		// Publish event via parent context as well...
    		if (this.parent != null) {
    			if (this.parent instanceof AbstractApplicationContext) {
    				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    			}
    			else {
    				this.parent.publishEvent(event);
    			}
    		}
    	}
    

      

    SimpleApplicationEventMulticaster: 应用事件广播器

    @Override
    	public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { // 根据event和type找到对应的监听器,并通知监听器
    			Executor executor = getTaskExecutor();
    			if (executor != null) {
    				executor.execute(new Runnable() {
    					@Override
    					public void run() {
    						invokeListener(listener, event);
    					}
    				});
    			}
    			else {
    				invokeListener(listener, event);
    			}
    		}
    	}
    

      

    4. spring 事件的消费者 ApplicationEventListener extend EventListener

  • 相关阅读:
    Nginx创建密码保护目录
    Android:Field can be converted to a local varible.
    创建用户故事地图(User Story Mapping)的8个步骤
    用户故事地图(User Story Mapping)之初体验
    Android必知必会--GreenDao缓存
    Windows下多线程数据同步互斥的有关知识
    OpenCV3.0 3.1版本的改进
    利用OpenCV的人脸检测给头像带上圣诞帽
    一些关于并行计算的科研思路
    Java中httpClient中三种超时设置
  • 原文地址:https://www.cnblogs.com/lzmrex/p/10682263.html
Copyright © 2020-2023  润新知