一些和業務邏輯無關的信息不應該放在硬編碼到程序中,一般將其放在ServletConfig或ServletContext。
在web.xml文件中配置ServletConfig和ServletContext參數:
<!-- 配置ServletContext參數 --><context-param> <param-name>email</param-name> <param-value>yaoyinglong@Gmail.com</param-value></context-param>
<servlet> <servlet-name>Test</servlet-name> <servlet-class>com.yyl.Test</servlet-class> <!-- 配置ServletConfig參數 --> <init-param> <param-name>email</param-name> <param-value>yaoyinglong@gmail.com</param-value> </init-param></servlet>
我們可以清楚的看到:ServletConfig參數配置在<servlet> 節點內部;而ServletContext參數配置在<servlet> 節點外部。
使用ServletConfig和ServletContext參數:
String servletConfigEmail=getServletConfig().getInitParameter("email");String servletContextEmail=getServletContext().getInitParameter("email");
不用說大家值也只那行去那個參數了。
ServletConfig和ServletContext參數的使用范圍:
ServletConfig參數:
①只可以在配置了它的servlet中可用;
②在java對象變為Servlet之前不可用(init函數有兩個版本,一般情況下不要覆蓋接受ServletConfig對象的那個版本嗎,即是要覆蓋也應該加上super.init(ServletConfig))。
③ServletConfig參數只在Servlet初始化是讀取一次,中途不能修改。
ServletContext對Web應用中的所有servlet和jsp都可用。
1.2 ServletConfig和ServletContext舉例這兩個對象非常重要,當我們程序需要讀取配置文件的時候便可以將在這里配置配置文件的路徑,下面以SPRing配置來說明:
我們如果通過MyEclipse使用Spring框架時,它會幫我們將Spring配置好,無需勞您大駕親自動手,但是如果你使用的是Eclipse的時候,抱歉,它可沒那么貼心了,只能我們自己手動來配了,無論是IDE幫我們配還是我們自己手動來陪,很多時候都是Ctrl+C和Ctrl+V,可是你知道Spring是怎么做的嗎?知道的請略過,或者您可以看看我說的是不是正確,指出錯誤之處(感激不盡?。?!),不知道的就請跟著我一起看看吧:
首先來看為什么要在web.xml中配置Spring:
不在web.xml中配置Spring時,我們要獲取配置在Spring的bean時我們是這樣做的:
import org.springframework.beans.factory.BeanFactory;import org.springframework.context.support.ClassPathXmlapplicationContext;public class Test { public static void main(String[] args) { BeanFactory beanFactory=new ClassPathXmlApplicationContext("appclicationContext.xml"); beanFactory.getBean("beanId"); }}
C/S端可以這么做,那么B/S端呢?我們可以用一個Servlet來實現:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BeanFactory beanFactory=new ClassPathXmlApplicationContext("applicationContext.xml"); getServletContext().setAttribute("beanFactory", beanFactory);}
這樣配置了之后,在Web應用的所有JSP和Servlet中都可以使用BeanFactory了。
還有一種配置方式就是我們下面要講到的監聽器(可以先看一下下面的內容在回來):
@Overridepublic void contextDestroyed(ServletContextEvent sce) { BeanFactory beanFactory=new ClassPathXmlApplicationContext("applicationContext.xml"); sce.getServletContext().setAttribute("beanFactory", beanFactory);}
大家有沒有發現無論用什么方法配,代碼都是一樣的。Spring框架開發者,也發現了這件事情,于是他們就把這件事情給做了(他們提供了后兩種的實現),我們都知道,Servlet和監聽器都是要在web.xml中配置的。因此我們工作就是把Spring框架開發者幫我們實現好的Servlet和監聽器配置到web.xml中。
注:我這里只是簡單的說明最核心的部分,強大的Spring要做的工作遠比我這里做的多的多,并且我這里將application.xml配置文件的路徑硬編碼到了程序里,這是不好的,應該使用我們現在講的ServletConfig和ServletContext參數配置到xml文件中。
我們看看Spring到底是怎么做的:
哈哈,我沒有騙大家吧,Spring為我們實現了Servlet和Listener的配置方式。不過大多數情況下我們都是用Listener來配置的。那我們進到這個監聽器中看看:
public class ContextLoaderListener implements ServletContextListener { private ContextLoader contextLoader; public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); this.contextLoader.initWebApplicationContext(event.getServletContext()); } protected ContextLoader createContextLoader() { return new ContextLoader(); } public ContextLoader getContextLoader() { return this.contextLoader; } public void contextDestroyed(ServletContextEvent event) { if (this.contextLoader != null) { this.contextLoader.closeWebApplicationContext(event.getServletContext()); } }}
我們發現他在Web應用啟動時,做了兩件事情:創建ContextLoader類,然后調用它的initWebApplicationContext方法,進入該方法:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { // 考慮到篇幅的太大故將一些我們暫時不關心的部分刪掉了…… try { // Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); // 考慮到篇幅的太大故將一些我們暫時不關心的部分刪掉了……
}
從黃底加粗的代碼中我們可以清楚的看到:先創建了WebApplicationContext對象,然后將其保存到了servletContext中(即Application范圍內)。以后Struts2和Spring繼承插件就可以從Application中獲取BeanFactory,通過BeanFactory取得Ioc容器中的Actoin對象,這樣Action的依賴對象都會被注入。
那么我再跟蹤createWebApplicationContext函數:
protected WebApplicationContext createWebApplicationContext( ServletContext servletContext, ApplicationContext parent) throws BeansException { Class contextClass = determineContextClass(servletContext); // 考慮到篇幅的太大故將一些我們暫時不關心的部分刪掉了……
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setParent(parent); wac.setServletContext(servletContext); //這里讀取web.xml文件中的 <context-param>節點中的值 wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM)); customizeContext(servletContext, wac); wac.refresh(); return wac; }
從黃底加粗的代碼指示我們必須在web.xml文件中配置<context-param>參數,至于配什么呢,<param-value>參數的值我們知道,肯定是要applicationContext.xml文件的路徑,參數的名字是什么呢?往后看,它從那個參數讀,我們就用那個參數組為的<param-name>值。
查看CONFIG_LOCATION_PARAM常量:
所以我們的<param-name>的值為contextConfigLocation。
誒!前面我們不是說創建BeanFactory嗎?怎么這里創建的是WebApplicationContext呢?經跟蹤發現它繼承自BeanFactory,主要使用BeanFactory的getBean方法來獲取Bean。
這下明白我在web.xml中使用監聽器配置Spring的含義了吧。
那么如果我們使用Servlet怎么配置呢?(不懂的可以留言,這里就不浪費篇幅了)。
1.3 ServletContext不是線程安全的應用中的每一部分都能訪問到ServletContext,因此,必要時應該對其同步:
synchronized (getServletContext()) { //業務邏輯代碼}2. 監聽器(Listener)
所謂監聽者就是,當你做某一件事情的時候,另一個類關注著你,并且采取相應的行動。
2.1 ServletContextListener查看API可知,它監聽Web應用初始化和Web應用銷毀動作,那我們就可以指示該監聽者,在Web應用初始化和Web應用銷毀時幫我們干我們想干的事情:
public class TestServletContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("Oh,my god! I was killed"); } @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("houhou, God created me"); String email=sce.getServletContext().getInitParameter("email"); System.out.println("My Email is "+email); }}
這樣它就能聽我們的話了嗎?還不行,因為Tomcat不會看你實現了ServletContextListener接口就會讓它去監視Web應用的初始化和銷毀。Tomcat只會處理你在web.xml文件中配置了的事情。因此還需在web.xml中配置監聽:
在節點下添加:
<listener> <listener-class>com.yyl.TestServletContextListener</listener-class> </listener>
現在配置就完成了,ServletContextListener的實現者已經為我所用了,不行你看看:
當我啟動Tomcat時:
當我們關閉Tomcat時:
到這里您是不是有個疑問:Tomcat怎么知道你配的這個com.yyl.TestServletContextListener是用來監聽Web應用的創建于銷毀動作呢,即這個監聽者是ServletContext監聽者?因為Servlet還有很多其他監聽者(后面會一一登場亮相)。這是因為Web容器會會檢查類,檢查它繼承了那個監聽接口,或者多個監聽接口,據此明確它來監聽什么類型的事件。
3. 監聽器有8種(8種接口)ServletContextAttributeListener:監聽在ServletContext對象中添加、刪除、替換屬性的動作。
HttpsessionListener:監聽Web應用Session的創建于銷毀。據此可以知道有多少并發用戶。
ServletRequestListener:監聽瀏覽器請求Servlet動作。
ServletRequestAttrubuteListener:監聽在ServletRequest對象中請求中添加、刪除、替換屬性的動作。
HttpSessionBindingListener:屬性本身在被添加到session中或從session中刪除時得到通知。
HttpSesionAttributeListener:監聽在HttpSession中增加、刪除、替換屬性的動作。
servletContextListener:監聽Web應用創建或撤銷動作。
HttpSessionActivationListener:當一個Session被遷移到另一個JVM中通知實現了該接口的屬性做好準備。
今天實在沒有精力一一舉例了,下篇吧!
新聞熱點
疑難解答