1. 简单剖析JSP中session、appliactioon创建过程
在JSP中使用的session、application、pageContext的创建其实是在Servlet容器中实现的,JSP页面被在Servlet容器中会被转换为HttpServlet的一个子类(以tomcat为例,转换后的文件存储在apache-tomcat-*\work\Catalina\[项目IP]\[项目名称 ]\org\apache\jsp中)
通过如下代码截图可以看出去
Ø application是javax.servlet.ServletContext实例,通过pageContext.getServletContext()获取
Ø session是javax.servlet.http.HttpSession实例,通过pageContext.getSession()获取
详细内容可以通过JSP运行原理以及执行过程源码分析了解
监听器是典型的观察者设计模式的实现
Servlet和spring中我们熟知的listeners包括HttpSessionListener、ServletContextListener、ApplicationListener
Ø HttpSessionListener是对javax.servlet.http.HttpSession(session)的监听
Ø ServletContextListener是对javax.servlet.ServletContext(application)的监听
Ø ApplicationListener是对Spring的ApplicationContext的监听。
这些监听接口的监听方法会在它们所监听的内容状态发生变化时被调用,这些被监听的内容(session、application)在服务器启动时创建,在服务器关闭时销毁,所以就可以在对应的监听方法中实现系统的一系列初始化配置动作(后面会举例介绍)。
这些Listeners接口中都会有对应状态的监听方法,例如ServletContextListener
Ø publicvoid contextInitialized(ServletContextEventcontextEvent)在ServletContext创建时被调用
Ø publicvoidcontextDestroyed(ServletContextEvent contextEvent)在ServletContext被销毁时调用
【MyServletContextListener.java】
@Component("myServletContextListener") public class MyServletContextListener implements ServletContextListener { private Loggerlogger = LogManager.getLogger(MyServletContextListener.class); @Override publicvoidcontextInitialized(ServletContextEvent arg0) { logger.debug("ServletContext初始化开始"); logger.debug("一系列初始化操作......"); } @Override publicvoidcontextDestroyed(ServletContextEvent arg0) { logger.debug("ServletContext销毁"); logger.debug("一系列逆初始化操作......"); } }
【web.xml】加一句
<listener>
<listener-class>com.mlq.love.listener.MyServletContextListener</listener-class>
</listener>
启动服务器,查看log如下:
【MyHttpSessionListener.java】
import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { @Override publicvoidsessionCreated(HttpSessionEvent arg0) { } @Override publicvoidsessionDestroyed(HttpSessionEventarg0) { } }
【web.xml】
<listener>
<listener-class>com.mlq.love.listener.MyHttpSessionListener</listener-class>
</listener>
Web.xml中配置如下内容
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
查看ContextLoaderListener源码,发现ContextLoaderListener也实现了ServletContextListener接口,在contextInitialized方法中进行Spring的相关初始化操作:
Spring框架加载完成后会publishContextRefreshedEvent事件,spring容器的许多初始化工作在ContextLoaderListener中完成,包括初始化applicationContext.xml文件中配置的bean对象、初始化国际化相关的对象(MessageSource)等,当这些步骤执行完后,最后一个就是执行刷新上下文事件,代码Trace如下
(initWebApplicationContext(event.getServletContext()); public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { try { ... // Initialize message source for this context. initMessageSource(); // 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; } } } /** * Finish the refresh of this context, invoking the LifecycleProcessor's * onRefresh() method and publishing the * {@link org.springframework.context.event.ContextRefreshedEvent}. */ protected void finishRefresh() { // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); }
跟进finishRefresh方法可发现publishEvent(newContextRefreshedEvent(this));这行代码,此处就是刷新上下文的事件
【MyApplicationListener.java】
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component("MyApplicationListener") publicclassMyApplicationListenerimplements ApplicationListener<ContextRefreshedEvent> { Loggerlogger= LogManager.getLogger(MyApplicationListener.class); @Override publicvoidonApplicationEvent(ContextRefreshedEventevent) { logger.debug("监听到ContextRefreshedEvent事件"); } }
启动服务器,log如下:
【MyApplicationEvent.java】
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Component; @Component("myApplicationEvent") publicclassMyApplicationEventextends ApplicationEvent { Loggerlogger= LogManager.getLogger(MyApplicationEvent.class); privatestaticfinallongserialVersionUID= 7500024553335407309L; publicMyApplicationEvent(Object source) { super(source); } publicvoid testCustomerEvent(){ logger.debug("自定义事件被触发"); } }
【MyCustomerApplicationListener.java】
publicclassMyCustomerApplicationListenerimplements ApplicationListener { @Override publicvoidonApplicationEvent(ApplicationEvent event) { if(eventinstanceofMyApplicationEvent){ MyApplicationEventmyEvent = (MyApplicationEvent)event; myEvent.testCustomerEvent(); } } }