spring 容器启动-观察者模式

之前一篇文件简单的讲了一些spring容器的启动顺序以及父子容器,现在说的是一些有关spring容器启动时涉及的设计模式的思想-观察者模式

首先在web.xml文件中我们通过配置监听器来监听web容器的启动从而加载spring容器,并且spring中的一些监听事件和监听器也会同时被创建出来:

      <!-- 加载spring容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/applicationContext*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

//ServletContextEvent event  web程序应用上下文启动事件

初始化容器是首先调用的是ContextLoaderListener类中contextInitialized((ServletContextEvent event))

    /**
     * Initialize the root web application context.
     */
    public void contextInitialized(ServletContextEvent event) {
        this.contextLoader = createContextLoader();
        if (this.contextLoader == null) {
            this.contextLoader = this;
        }

//event.getServletContext()   获得web应用程序上下文      调用ContextLoader类中的initWebApplicationContext()方法

//目的是通过servletContext容器获得spring web application(容器)

        this.contextLoader.initWebApplicationContext(event.getServletContext());
    }

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            throw new IllegalStateException(
                    "Cannot initialize context because there is already a root application context present - " +
                    "check whether you have multiple ContextLoader* definitions in your web.xml!");
        }

        Log logger = LogFactory.getLog(ContextLoader.class);
        servletContext.log("Initializing Spring root WebApplicationContext");
        if (logger.isInfoEnabled()) {
            logger.info("Root WebApplicationContext: initialization started");
        }
        long startTime = System.currentTimeMillis();

        try {
            // Store context in local instance variable, to guarantee that
            // it is available on ServletContext shutdown.

//如果为空就创建一个spring web application

            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }

/

            if (this.context instanceof ConfigurableWebApplicationContext) {

              //重启容器, 其中会调用 refresh()方法来完成观察者模式的监听与实现

                configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);
            }

    }

      protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
   
        customizeContext(sc, wac);
        wac.refresh();

}

 

spring在容器中使用了观察者模式:

  spring事件:ApplicationEvent, 事件,该抽象类继承了EventObject,jdk建议所有的事件都应该继承自EventObject

  spring事件监听器:ApplicationLisener

Java代码  收藏代码

  1. public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {  
  2.   
  3.     /** 
  4.      * Handle an application event. 
  5.      * @param event the event to respond to 
  6.      */  
  7.     void onApplicationEvent(E event);  
  8.   
  9. }  

   该接口继承了EventListener接口,jdk建议所有的事件监听器都应该继承EventListener

 

  spring事件发布:ApplicationEventPublisher , ApplicationContext继承了该接口,在ApplicationContext的抽象类AbstractApplicationContext中做了实现

Java代码  收藏代码

  1. public interface ApplicationEventPublisher {  
  2.   
  3.     /** 
  4.      * Notify all listeners registered with this application of an application 
  5.      * event. Events may be framework events (such as RequestHandledEvent) 
  6.      * or application-specific events. 
  7.      * @param event the event to publish 
  8.      * @see org.springframework.web.context.support.RequestHandledEvent 
  9.      */  
  10.     void publishEvent(ApplicationEvent event);  
  11.   
  12. }  

  

  AbstractApplicationContext类中publishEvent方法实现:

 

Java代码  收藏代码

  1. public void publishEvent(ApplicationEvent event) {  
  2.     Assert.notNull(event, "Event must not be null");  
  3.     if (logger.isTraceEnabled()) {  
  4.         logger.trace("Publishing event in " + getDisplayName() + ": " + event);  
  5.     }  
  6.                //事件广播委托给ApplicationEventMulticaster来进行  
  7.     getApplicationEventMulticaster().multicastEvent(event);  
  8.     if (this.parent != null) {  
  9.         this.parent.publishEvent(event);  
  10.     }  
  11. }  

   由上代码可知,AbstractApplicationContext类并没有具体的做事件广播,而是委托给ApplicationEventMulticaster来进行,ApplicationEventMulticaster的multicastEvent()方法实现如下:

Java代码  收藏代码

  1. public void multicastEvent(final ApplicationEvent event) {  
  2.     for (final ApplicationListener listener : getApplicationListeners(event)) {  
  3.         Executor executor = getTaskExecutor();  
  4.         if (executor != null) {  
  5.             executor.execute(new Runnable() {  
  6.                 public void run() {  
  7.                     listener.onApplicationEvent(event);  
  8.                 }  
  9.             });  
  10.         }  
  11.         else {  
  12.             listener.onApplicationEvent(event);  
  13.         }  
  14.     }  
  15. }  

 获得listener集合,遍历listener触发事件Executor接口有多个实现类,可以支持同步或异步广播事件

 

 

 

现在大家可能有个疑问,spring容器是怎么根据事件去找到事件对应的事件监听器呢?  接着上面的refresh() 讲

在spring容器初始化的时候,

  1. public void refresh() throws BeansException, IllegalStateException {  
  2.     synchronized (this.startupShutdownMonitor) {  
  3.         // Prepare this context for refreshing.  
  4.         prepareRefresh();  
  5.   
  6.         // Tell the subclass to refresh the internal bean factory.  
  7.         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.   
  9.         // Prepare the bean factory for use in this context.  
  10.         prepareBeanFactory(beanFactory);  
  11.   
  12.         try {  
  13.             // Allows post-processing of the bean factory in context subclasses.  
  14.             postProcessBeanFactory(beanFactory);  
  15.   
  16.             // Invoke factory processors registered as beans in the context.  
  17.             invokeBeanFactoryPostProcessors(beanFactory);  
  18.   
  19.             // Register bean processors that intercept bean creation.  
  20.             registerBeanPostProcessors(beanFactory);  
  21.   
  22.             // Initialize message source for this context.  
  23.             initMessageSource();  
  24.                                  
  25.                                //初始化一个事件注册表  
  26.             // Initialize event multicaster for this context.  
  27.             initApplicationEventMulticaster();  
  28.   
  29.             // Initialize other special beans in specific context subclasses.  
  30.             onRefresh();  
  31.                                  
  32.                                //注册事件监听器  
  33.             // Check for listener beans and register them.  
  34.             registerListeners();  
  35.   
  36.             // Instantiate all remaining (non-lazy-init) singletons.  
  37.             finishBeanFactoryInitialization(beanFactory);  
  38.   
  39.             // Last step: publish corresponding event.  
  40.             finishRefresh();  
  41.         }  
  42.   
  43.         catch (BeansException ex) {  
  44.             // Destroy already created singletons to avoid dangling resources.  
  45.             destroyBeans();  
  46.   
  47.             // Reset 'active' flag.  
  48.             cancelRefresh(ex);  
  49.   
  50.             // Propagate exception to caller.  
  51.             throw ex;  
  52.         }  
  53.     }  
  54. }

以下是自己写一个spring的监听器和事件

// 所有的事件都必须继承EventObject

  public abstract class ApplicationEvent extends EventObject {}

public class MyTestEvent extends ApplicationEvent {
    private String name;
    private String id;
    public MyTestEvent(Object source, String name, String id) {
        super(source);
        this.name = name;
        this.id = id;
        System.out.println("tetetetet");
    }
    public MyTestEvent(Object source) {
        super(source);
    }
}

//监听器

public class MyTestListener implements ApplicationListener<ApplicationEvent>{
    @Override
    public void onApplicationEvent(ApplicationEvent arg0) {
        if(arg0 instanceof MyTestEvent){
            MyTestEvent myTestEvent = (MyTestEvent)arg0;
            System.out.println(myTestEvent.getId());
        }else{
            System.out.println("nonono");
        }
    }

}

spring-bean.xml

     <bean id="myTestEvent" class="com.springinaction.springidol.bean.MyTestEvent">
         <constructor-arg value ="heee"/>
         <constructor-arg value ="name"/>
         <constructor-arg value ="34"/>
     </bean>
     <bean id="myTestListener" class="com.springinaction.springidol.bean.MyTestListener"/>
    

测试方法

public class testBean {

    
    @Test
    public void test() {
     ApplicationContext ctx = new ClassPathXmlApplicationContext("/spring-bean.xml");
     //测试监听事件
     MyTestEvent myTestEvent = (MyTestEvent)ctx.getBean("myTestEvent");
      //MyTestEvent myTestEvent = new MyTestEvent("hello", "test", "2");
      //将事件放进applicationContext中中   只要容器启动就会触发监听  
      ctx.publishEvent(myTestEvent);
      
    }

}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坑里水库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值