您的位置:首页 > 编程语言 > Java开发

spring 容器启动-观察者模式

2017-06-25 00:53 330 查看
之前一篇文件简单的讲了一些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类中的[b]initWebApplicationContext()方法[/b]

//目的是通过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代码  


public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {  
  
    /** 
     * Handle an application event. 
     * @param event the event to respond to 
     */  
    void onApplicationEvent(E event);  
  
}  

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

 

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

Java代码  


public interface ApplicationEventPublisher {  
  
    /** 
     * Notify all listeners registered with this application of an application 
     * event. Events may be framework events (such as RequestHandledEvent) 
     * or application-specific events. 
     * @param event the event to publish 
     * @see org.springframework.web.context.support.RequestHandledEvent 
     */  
    void publishEvent(ApplicationEvent event);  
  
}  

  

  AbstractApplicationContext类中publishEvent方法实现:

 

Java代码  


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

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

Java代码  


public void multicastEvent(final ApplicationEvent event) {  
    for (final ApplicationListener listener : getApplicationListeners(event)) {  
        Executor executor = getTaskExecutor();  
        if (executor != null) {  
            executor.execute(new Runnable() {  
                public void run() {  
                    listener.onApplicationEvent(event);  
                }  
            });  
        }  
        else {  
            listener.onApplicationEvent(event);  
        }  
    }  
}  

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

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

在spring容器初始化的时候,

public void refresh() throws BeansException, IllegalStateException {  
    synchronized (this.startupShutdownMonitor) {  
        // Prepare this context for refreshing.  
        prepareRefresh();  
  
        // Tell the subclass to refresh the internal bean factory.  
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  
        // Prepare the bean factory for use in this context.  
        prepareBeanFactory(beanFactory);  
  
        try {  
            // Allows post-processing of the bean factory in context subclasses.  
            postProcessBeanFactory(beanFactory);  
  
            // Invoke factory processors registered as beans in the context.  
            invokeBeanFactoryPostProcessors(beanFactory);  
  
            // Register bean processors that intercept bean creation.  
            registerBeanPostProcessors(beanFactory);  
  
            // Initialize message source for this context.  
            initMessageSource();  
                                 
                               //初始化一个事件注册表  
            // Initialize event multicaster for this context.  
            initApplicationEventMulticaster();  
  
            // Initialize other special beans in specific context subclasses.  
            onRefresh();  
                                 
                               //注册事件监听器  
            // Check for listener beans and register them.  
            registerListeners();  
  
            // Instantiate all remaining (non-lazy-init) singletons.  
            finishBeanFactoryInitialization(beanFactory);  
  
            // Last step: publish corresponding event.  
            finishRefresh();  
        }  
  
        catch (BeansException ex) {  
            // Destroy already created singletons to avoid dangling resources.  
            destroyBeans();  
  
            // Reset 'active' flag.  
            cancelRefresh(ex);  
  
            // Propagate exception to caller.  
            throw ex;  
        }  
    }  
}

以下是自己写一个spring的监听器和事件
// 所有的事件都必须继承[b]EventObject
[/b]

  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);

      

    }

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: