<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Hello Java

     

    2006年7月4日

    一個用于J2EE應用程序的異常處理框架(轉載)

    轉自:http://dev2dev.bea.com.cn/techdoc/20060601803.html
    一個用于J2EE應用程序的異常處理框架


    時間:2006-06-01
    作者:ShriKant Vashishtha
    瀏覽次數: 1184
    本文關鍵字:J2EE,?Struts,?RuntimeException,?design patterns,?最佳實踐,?異常處理,?包裝,?設計模式,?外觀,?模板方法
    文章工具
    推薦給朋友?推薦給朋友
    打印文章?打印文章

      在大多數Java項目中,大部分代碼都是樣板代碼。異常處理就屬于此類代碼。即使業務邏輯只有3到4行代碼,用于異常處理的代碼也要占10到 20行。本文將討論如何讓異常處理保持簡單和直觀,使開發人員可以專心于開發業務邏輯,而不是把時間浪費在編寫異常處理的樣板代碼上。本文還將說明用于在 J2EE環境中創建和處理異常的基礎知識和指導原則,并提出了一些可以使用異常解決的業務問題。本文將使用Struts框架作為表示實現,但該方法適用于任何表示實現。

    使用checked和unchecked異常的場景

      您是否曾經想過,為什么要在編寫好的代碼塊周圍放置一個try-catch塊,即便明知道無法對這些異常進行什么處理,而只滿足于把它們放在 catch塊中?您可能想知道,為什么不能把這項工作放在一個集中的地方完成?在大多數情況下,這個地方對于J2EE應用程序來說就是一個前端控制器。 換句話說,開發人員不會因為它們而受到干擾,因為根本不必很多地過問它們。但是,如果一個方法名稱包含一個throws子句,會出現什么情況呢?開發人員 或者必須捕捉這些異常,或者把它們放在自己的方法的throws子句中。這就是痛苦的根源!幸運的是,Java API有一類叫做unchecked exception的異常,它們不必捕捉。但是,仍然存在一個問題:根據什么來決定哪些是checked異常,哪些是unchecked異常?下面給出一 些指導原則:

    • 終端用戶無法采取有效操作的異常應該作為unchecked異常。例如,致命的和不可恢復的異常就應該 是unchecked。把XMLParseException(在解析XML文件時拋出)作為checked異常沒有任何意義,因為惟一能夠采取的措施就 是基于異常跟蹤來解決根本問題。通過擴展java.lang.RuntimeException,可以創建自定義的unchecked異常。
    • 在 應用程序中,與用戶操作相關的異常應該是checked異常。checked異常要求客戶端來捕捉它們。您可能會問,為什么不把所有異常都當作是 unchecked。這樣做的問題在于,其中一些異常無法在正確的位置被捕捉到。這會帶來更大的問題,因為錯誤只有在運行時才能被識別。checked異 常的例子有業務確認異常、安全性異常等等。

    異常拋出策略

    只捕捉基本應用程序異常(假定為BaseAppException)并在throws子句中聲明

      在大多數J2EE應用程序中,關于針對某個異常應該在哪一界面上顯示哪條錯誤消息的決策只能在表示層中做出。這會帶來另一個問題:為什么我們不能把這種決策放在一個公共的地方呢?在J2EE應用程序中,前端控制器就是一個進行常見處理的集中位置。

       此外,必須有一種用于傳播異常的通用機制。異常也需要以一種普適的方式得到處理。為此,我們始終需要在控制器端捕捉基本應用程序異常 BaseAppException。這意味著我們需要把BaseAppException異常(只有這個異常)放入可以拋出checked異常的每個方法 的throws子句中。這里的概念是使用多態來隱藏異常的實際實現。我們在控制器中捕捉BaseAppException,但是所拋出的特定異常實例可能 是幾個派生異常類中的任意一個。借助于這種方法,可以獲得許多異常處理方面的靈活性:

    • 不需要在throws子句中放入大量的checked異常。throws子句中只需要有一個異常。
    • 不需要再對應用程序異常使用混亂的catch塊。如果需要處理它們,一個catch塊(用于BaseAppException)就足夠了。
    • 開發人員不需要親自進行異常處理(日志記錄以及獲取錯誤代碼)。這種抽象是由ExceptionHandler完成的,稍后本文會就此點進行討論。
    • 即使稍后把更多異常引入到方法實現中,方法名稱也不會改變,因此也不需要修改客戶端代碼,否則就會引起連鎖反應。然而,拋出的異常需要在方法的Javadoc中指定,以便讓客戶端可以看到方法約束。

      下面給出拋出checked異常的一個例子:

    public void updateUser(UserDTO userDTO) 
    throws BaseAppException{
    UserDAO userDAO = new UserDAO();
    UserDAO.updateUser(userDTO);
    ...
    if(...)
    throw new RegionNotActiveException(
    "Selected region is not active");
    }

    Controller Method:
    ...
    try{
    User user = new User();
    user.updateUser(userDTO);
    }catch(BaseAppException ex){
    //ExceptionHandler is used to handle
    //all exceptions derived from BaseAppException
    }
    ...

      迄今為止,我們已經說明,對于所有可能拋出checked異常并被Controller調用的方法,其throws子句中應該只包含 checked異常。然而,這實際上暗示著我們在throws子句中不能包含其他任何應用程序異常。但是,如果需要基于catch塊中某種類型的異常來執 行業務邏輯,那又該怎么辦呢?要處理這類情況,方法還可以拋出一個特定異常。記住,這是一種特例,開發人員絕對不能認為這是理所當然的。同樣,此處討論的 應用程序異常應該擴展BaseAppException類。下面給出一個例子:

    CustomerDAO method:
    //throws CustomerNotActiveException along with
    //BaseAppException
    public CustomerDTO getCustomer(InputDTO inputDTO)
    throws BaseAppException,
    CustomerNotActiveException {
    . . .
    //Make a DB call to fetch the customer
    //details based on inputDTO
    . . .
    // if not details found
    throw new CustomerNotActiveException(
    "Customer is not active");
    }

    Client method:

    //catch CustomerNotActiveException
    //and continues its processing
    public CustomerDTO getCustomerDetails(
    UserDTO userDTO)
    throws BaseAppException{
    ...
    CustomerDTO custDTO = null;
    try{
    //Get customer details
    //from local database
    customerDAO.getCustomerFromLocalDB();
    }catch(CustomerNotActiveException){
    ...
    return customerDAO
    .activateCustomerDetails();
    }
    }

    在web應用程序層次上處理unchecked異常

      所有unchecked異常都應該在web應用程序層次上進行處理。可以在web.xml文件中配置web頁面,以便當應用程序中出現unchecked異常時,可以把這個web頁面顯示給終端用戶。

    把第三方異常包裝到特定于應用程序的異常中

      當一個異常起源于另一個外部接口(組件)時,應該把它包裝到一個特定于應用程序的異常中,并進行相應處理。

      例子:

    try {
    BeanUtils.copyProperties(areaDTO, areaForm);
    } catch (Exception se) {
    throw new CopyPropertiesException(
    "Exception occurred while using
    copy properties", se);
    }

      這里,CopyPropertiesException擴展了java.lang.RuntimeException,我們將會記錄它。我們捕 捉的是Exception,而不是copyProperties方法可以拋出的特定checked異常,因為對于所有這些異常來說,我們都會拋出同一個 unchecked CopyPropertiesException異常。

    過多異常

      您可能想知道,如果我們為每條錯誤消息創建一個異常,異常類自身是否會溢出呢?例如,如果“Order not found”是OrderNotFoundException的一條錯誤消息,您肯定不會讓CustomerNotFoundException的錯誤消 息為“Customer not found”,理由很明顯:這兩個異常代表同樣的意義,惟一的區別在于使用它們的上下文不同。所以,如果可以在處理異常時指定上下文,我們無疑可以把這些 異常合并為一個RecordNotFoundException。下面給出一個例子:

    try{
    ...
    }catch(BaseAppException ex){
    IExceptionHandler eh =ExceptionHandlerFactory
    .getInstance().create();
    ExceptionDTO exDto = eh.handleException(
    "employee.addEmployee", userId, ex);
    }

      在這里,employee.addEmployee上下文將被附加給一個上下文敏感的異常的錯誤代碼,從而產生惟一的錯誤代碼。例如,如果 RecordNotFoundException的錯誤代碼是errorcode.recordnotfound,那么這個上下文的最終錯誤代碼將變為 errorcode.recordnotfound.employee.addEmployee,它對于這個上下文是惟一的錯誤代碼。

       然而,我們要給出一個警告:如果您準備在同一個客戶端方法中使用多個接口,而且這些接口都可以拋出RecordNotFoundException異常, 那么想要知道是哪個實體引發了這個異常就變得十分困難。如果業務接口是公共的,而且可以被各種外部客戶端使用,那么建議只使用特定的異常,而不使用像 RecordNotFoundException這樣的一般性異常。特定于上下文的異常對于基于數據庫的可恢復異常來說非常有用,因為在這種情況下,異常 類始終是相同的,不同的只有它們出現的上下文。

    J2EE應用程序的異常層次結構

      正如前面討論的那樣,我們需要定義一個異常基類,叫做BaseAppException,它包含了所有應用程序異常的默認行為。我們將把這個基 類放到所有可能拋出checked異常的方法的throws子句中。應用程序的所有checked異常都應該是這個基類的子類。有多種定義錯誤處理抽象的 方式。然而,其中的區別更多地是與業務類而不是與技術有關。對錯誤處理的抽象可分為以下幾類。所有這些異常類都是從BaseAppException派生 而來。

    checked異常

    • 業務異常:執行業務邏輯時出現的異常。BaseBusinessException是這類異常的基類。
    • 數據庫異常:與持久化機制進行交互時拋出的異常。BaseDBException是這類異常的基類。
    • 安全性異常:執行安全性操作時出現的異常。這類異常的基類是BaseSecurityException。
    • 確認異常:在從終端用戶處獲得確認以執行某個特定任務時使用。這類異常的基類是BaseConfirmationException。

    unchecked異常

    • 系統異常:有時候我們希望使用unchecked異常。例如下面的 情況:不想親自處理來自第三方庫API的異常,而是希望把它們包裝在unchecked異常中,然后拋出給控制器。有時會出現配置問題,這些問題也不能由 客戶端進行處理,而應該被當作unchecked異常。所有自定義的unchecked異常都應該擴展自 java.lang.RuntimeException類。

    表示層上的異常處理

      表示層獨自負責決定對一個異常采取什么操作。這種決策涉及到識別拋出異常的錯誤代碼。此外,我們還需要知道在處理錯誤之后應該把錯誤消息重定向到哪一界面。

      我們需要對基于異常類型獲得錯誤代碼這個過程進行抽象。必要時還應該執行日志記錄。我們把這種抽象稱之為ExceptionHandler。它基于“四人幫”(Gang of Four,GOF) 外觀模式(《Design Patterns》 一書中說,該模式是用于“為子系統中的一組接口提供一個統一接口。外觀定義了一個更高級別的接口,使子系統變得更加易于使用。”),是用于處理所有派生自 BaseAppException的異常的整個異常處理系統的外觀。下面給出一個在Struts Action方法中進行異常處理的例子:

    try{ 
    ...
    DivisionDTO storeDTO = divisionBusinessDelegate
    .getDivisionByNum(fromDivisionNum);
    }catch(BaseAppException ex){
    IExceptionHandler eh = ExceptionHandlerFactory
    .getInstance().create();
    String expContext = "divisionAction.searchDivision";
    ExceptionDTO exDto = eh.handleException(
    expContext , userId, ex);
    ActionErrors errors = new ActionErrors();
    errors.add(ActionErrors.GLOBAL_ERROR
    ,new ActionError(
    exDto.getMessageCode()));
    saveErrors(request, errors);
    return actionMapping.findForward(
    "SearchAdjustmentPage");
    }

      如果更仔細地觀察我們剛剛編寫的異常處理代碼,您可能會意識到,為每個Struts方法編寫的代碼是十分相似的,這也是一個問題。我們的目標是盡可能地去掉樣板代碼。我們需要再次對它進行抽象。

      解決方案是使用模板方法(Template Method)設計模式(引自GOF:“它用于實現一個算法的不變部分,并把可變的算法部分留給子類來實現。”)。我們需要一個包含模板方法形式算法的基 類。該算法將包含用于BaseAppException的try-catch塊和對dispatchMethod方法的調用,方法實現(委托給派生類)如 下面的基于Struts的Action中所示:

    public abstract class BaseAppDispatchAction 
    extends DispatchAction{
    ...
    protected static ThreadLocal
    expDisplayDetails = new ThreadLocal();

    public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception{
    ...
    try{
    String actionMethod = request
    .getParameter(mapping.getParameter());
    finalDestination =dispatchMethod(mapping,
    form, request, response,actionMethod);
    }catch (BaseAppException Ex) {
    ExceptionDisplayDTO expDTO =
    (ExceptionDisplayDTO)expDisplayDetails
    .get();
    IExceptionHandler expHandler =
    ExceptionHandlerFactory
    .getInstance().create();
    ExceptionDTO exDto = expHandler
    .handleException(
    expDTO.getContext(), userId, Ex);
    ActionErrors errors = new ActionErrors();
    errors.add(ActionErrors.GLOBAL_ERROR,
    new ActionError(exDto
    .getMessageCode()));
    saveErrors(request, errors);
    return mapping.findForward(expDTO
    .getActionForwardName());
    } catch(Throwable ex){
    //log the throwable
    //throw ex;
    } finally {
    expDisplayDetails.set(null);
    }

      在Struts中,DispatchAction::dispatchMethod方法用于把請求轉發給正確的Action方法,叫做actionMethod。

       我們假定從一個HTTP請求獲得searchDivision作為actionMethod:dispatchMethod將在 BaseAppDispatchAction的派生Action類中把請求分派給searchDivision方法。在這里,您可以看到,異常處理僅在基 類中完成,而派生類則只實現Action方法。這采用了模板方法設計模式,在該模式中,異常處理部分是保持不變的,而dispatchMethod方法的 實際實現(可變部分)則交由派生類完成。

      修改后的Struts Action方法如下所示:

    ... 
    String exceptionActionForward =
    "SearchAdjustmentPage";
    String exceptionContext =
    "divisionAction.searchDivision";

    ExceptionDisplayDTO expDTO =
    new ExceptionDisplayDTO(expActionForward,
    exceptionContext);
    expDisplayDetails.set(expDTO);
    ...
    DivisionDTO divisionDTO =divisionBusinessDelegate
    .getDivisionByNum(fromDivisionNum);
    ...

      現在它看起來相當清晰。因為異常處理是在一個集中的位置上(BaseAppDispatchAction)完成的,手動錯誤可能造成的影響也降至最低。

      然而,我們需要設置異常上下文和ActionForward方法的名稱,如果有異常出現,請求就會被轉發到該方法。我們將在ThreadLocal變量expDisplayDetails中設置這些內容。

       但是,為什么要使用java.lang.ThreadLocal變量呢?expDisplayDetails是 BaseAppDispatchActiion類中的一個受保護數據成員,這也是它需要是線程安全的原因。java.lang.ThreadLocal對 象在這里便可派上用場。

    異常處理程序

      在上一部分中,我們討論了如何對異常處理進行抽象。下面給出一些應該滿足的約束:

    • 識別異常類型并獲得相應的錯誤代碼,該錯誤代碼可用于顯示一條消息給終端用戶。
    • 記錄異常。底層的日志記錄機制被隱藏,可以基于一些環境屬性對其進行配置。

      您可能已經注意到了,我們在表示層中捕捉的惟一異常就是BaseAppException。由于所有checked異常都是 BaseAppException的子類,這意味著我們要捕捉BaseAppException的所有派生類。基于類名稱來識別錯誤代碼再容易不過了。

    //exp is an object of BaseAppException
    String className = exp.getClass().getName();

      可以基于異常類的名稱在一個XML文件(exceptioninfo.xml)中對錯誤代碼進行配置。下面給出異常配置的一個例子:

    <exception name="EmployeeConfirmationException">
    <messagecode>messagecode.laborconfirmation</messagecode>
    <confirmationind>true</confirmationind>
    <loggingtype>nologging</loggingtype>
    </exception>

      正如您看到的那樣,我們把這個異常變為顯式,要使用的消息代碼是messagecode.employeeconfirmation。然后,為了實現國際化的目的,可以從ResourceBundle提取實際的消息。我們很清楚,不需要對這類異常執行日志記錄,因為它只是一條確認消息,而不是一個應用程序錯誤。

      讓我們看一看上下文敏感異常的一個例子:

    <exception name="RecordNotFoundException">
    <messagecode>messagecode.recordnotfound</messagecode>
    <confirmationind>false</confirmationind>
    <contextind>true</contextind>
    <loggingtype>error</loggingtype>
    </exception>

      在這里,這個表達式的contextind為true。在handleException方法中傳遞的上下文可用于創建惟一的錯誤代碼。例如, 如果我們把order.getOrder當作一個上下文進行傳遞,結果得到的消息代碼就是異常的消息代碼和所傳遞的上下文的串聯。因此,我們獲得了一個像 messagecode.recordnotfound.order.getOrder這樣的惟一消息代碼。

      對于每個異常來說,可以把 exceptioninfo.xml 中的數據封裝到一個叫做ExceptionInfoDTO的數據傳輸對象(data transfer object,DTO)。現在,我們還需要一個占位符,用于緩存這些對象,因為我們不想在異常出現時反復解析XML文件和創建對象。這項工作可以委托給一 個叫做ExceptionInfoCache的類來完成,這個類將會在從exceptioninfo.xml文件讀取ExceptionInfoDTO對 象信息之后緩存所有這些對象。

      現在您是否弄清楚了這整個過程?這種方法的核心部分是ExceptionHandler實現,該實現將使 用封裝在ExceptionInfoDTO中的數據來獲取消息代碼,創建ExceptionDTO對象,然后基于在給定異常的 ExceptionInfoDTO中指定的日志記錄類型來記錄它。

      下面是ExceptionHandler實現的handleException方法:

    public ExceptionDTO handleException(String userId,
    BaseAppException exp) {
    ExceptionDTO exDTO = new ExceptionDTO();
    ExceptionInfoCache ecache =
    ExceptionInfoCache.getInstance();
    ExceptionInfo exInfo = ecache
    .getExceptionInfo(
    ExceptionHelper.getClassName(exp));
    String loggingType = null;
    if (exInfo != null) {
    loggingType = exInfo.getLoggingType();
    exDTO.setConfirmation(exInfo
    .isConfirmation());
    exDTO.setMessageCode(exInfo
    .getMessageCode());
    }

    FileLogger logger = new FileLoggerFactory()
    .create();
    logger.logException(exp, loggingType);

      根據不同的業務需求,ExceptionHandler接口可以有多種實現。決定使用何種實現的任務可交由Factory來完成,特別是ExceptionHandlerFactory類。

    結束語

      如果缺乏全面的異常處理策略,一些特殊的異常處理塊便可能導致出現非標準的錯誤處理和不可維護的代碼。通過使用上面的方法,便可簡化J2EE應用程序中的異常處理過程。

    參考資料

    原文出處: http://www.onjava.com/pub/a/onjava/2006/01/11/exception-handling-framework-for-j2ee.html

    ?作者簡介

    ShriKant Vashishtha 當前是印度Tata Consultancy Services Limited (TCS)公司的解決方案架構師。

    posted @ 2006-07-04 11:15 Hello Java 閱讀(588) | 評論 (0)編輯 收藏

    2006年6月14日

    Servlet 2.4規范閱讀筆記(2-3章)

    第2章 The servlet Interface
    所有Servlet實現同一接口:Servlet,它有兩個直接的子類:GenericServlet和HttpServlet.
    2.1 Request Handle method
    基本的Servlet使用service()方法處理請求,因為可能有多個客戶的請求在service()中工作,所以開發者必須要考慮到并發的情況。
    SRV.2.1.1 HTTP Specific Request Handling Methods

    HttpServlet定義了以下7個方法:

    • doGet for handling HTTP GET requests
    • doPost for handling HTTP POST requests
    • doPut for handling HTTP PUT requests
    • doDelete for handling HTTP DELETE requests
    • doHead for handling HTTP HEAD requests
    • doOptions for handling HTTP OPTIONS requests
    • doTrace for handling HTTP TRACE requests
    SRV.2.1.2 Additional Methods
    ???
    關于Http的幾個附加命令HEAD,DELETE,PUT,OPTIONS,TRACE。
    SRV.2.1.3 Conditional GET Support
    這個”Conditional GET“指的是這樣的請求:只有所請求的資源在一個特定時間之后被修改過,才被發送給客戶端。
    HttpServlet里的getLastModified()方法提供了這方面的支持。
    SRV.2.2 Number of Instances
    ??? 在2.4之前的版本中,Servlet有兩種方式:
    ??? 第一種方式是對于一個Servlet,只有一個實例,這個實例可以同時服務多個用戶,這是默認的。
    ??? 另一種方式是一個Servlet的實例只能服務一個客戶,這樣就需要一個Servlet的Pool,當多個用戶連接時,需要建立多個Servlet實例。這種方式需要Servlet實現SingleThreadModel接口。
    ??? 以上兩種方式的比較:第一種方式需要考慮同步問題(因為一個Servlet的實例服務多個用戶,Servlet中的數據成員需要同步),第二種方式不需要考慮同步問題。
    ???
    SRV.2.3 Servlet Life Cycle
    ??? 1.載入:???
    ??? 應用服務器可能在啟動時載入Servlet或者在第一個請求到來時延遲加載,載入的方式也是使用類裝載器,和普通的Java Object沒有什么區別。
    ??? 2.初始化:
    ??? 初始化時可能遇到錯誤,這時會拋出ServletException或者UnaviliableException異常
    ??? 3.多線程:
    ??? 需要注意的一點是,最好不要對service()方法進行synchronize修飾。這樣的話就不能使用線程池,而必須對request序列化
    ??? 4.處理請求時的錯誤處理:
    ??? 如果在這時發生異常,可以發送UnavailableException或者ServletException,如果發送了 ServletException,服務器必須要想辦法清除request。如果發送了UnavailableException,有兩種選擇,如果是永 久的的無效,需要調用destroy(),并摧毀Servlet,如果這時客戶端訪問此Servlet,它將會收到404錯誤。如果是臨時的無效,容器需 要拒絕任何到此Servlet的請求,并且返回503錯誤
    ?? 5.線程安全的話題
    ??? request和response這兩個對象不是線程安全的,所以不要在service()方法外面使用它們,它們的引用不應該傳給另一個線程中的對象,如果一定要訪問它們,必須對使用這兩個對象的代碼進行同步。
    ??? 6.服務的結束
    ?? Servlet容器并不需要一直保持一個Servlet處于運行狀態,在釋放一個servlet時,會調用destroy方法,當調用destroy方法之前,容器會一直等到所有的線程都完成了在service()方法中的工作。
    第3章 Servlet Context
    SRV.3.1 Introduction to the ServletContext Interface
    Servlet Context,從Servlet的角度來看,可以理解為它所屬Web應用程序,ServletContext是一個接口,Servlet容器的提供商必須要實現這個接口。
    ServletContext能做什么呢?它可以把事件記錄到日志中,獲得資源的URL,還可以利用ServletContext存放一些所有Servlet都能共享的數據。
    ServletContext有一個路徑,例如http://www.mycorp.com/catalog,這里的cataqlog就是ServletContext的路徑,所有的對catalog的請求都會關聯到這個ServletContext.
    SRV.3.2 Scope of a ServletContext Interface

    在Servlet容器中,每個ServletContext通常只有一個實例。當Web容器是分布式的部署在多臺機器上時,那一個ServletContext在每個JVM上都有一個實例。
    在Servlet容器中,但沒有部署的Servlet也是允許的,這種Servlet屬于一個缺省的ServletContext,這種缺省的ServletContext不能被分布到多個JVM上。
    SRV.3.3 Initialization Parameters
    在ServletContext接口中,有兩個方法可以用來獲得初始化參數:
    ? getInitParameter
    ? getInitParameterNames
    SRV.3.4 Context Attributes
    在ServletContext中,有4個方法可以用來設置和管理ServletContext的屬性:
    ? setAttribute
    ? getAttribute
    ? getAttributeNames
    ? removeAttribute
    SRV.3.4.1 Context Attributes in a Distributed Container
    ServletContext中的屬性只在本地的JVM中有效,不能被分布式環境中運行于其它JVM中的Servlet訪問,如果需要在分布式環境中共享數據,可以把數據存放在Session,數據庫或EJB中。
    SRV.3.5 Resources
    資源指的是在Web應用程序中的一些靜態的內容,如靜態HTML頁面,圖片等等。ServletContext提供了兩個方法來訪問這些資源:
    ? getResource
    ? getResourceAsStream
    這兩個方法都接受一個String型參數,它指定了一個以"/"開頭的相對于這個ServletContext的資源路徑。資源可以放在同一服務器上,或者不同服務器上,或者在一個Web應用程序的WAR包中。
    需要注意的是,這兩個方法不能用來獲取動態內容,如果我們用這兩個方法去取一個JSP頁面,返回的將是JSP頁面的源代碼。
    getResourcePaths(String path)方法可以用來獲取一個資源列表。
    SRV.3.6 Multiple Hosts and Servlet Contexts
    Web服務器可能支持多個域名分享一個IP地址,這種配置叫做“虛擬主機”。在這種情況下,每個虛擬主機必須要有自己的ServletContext,而不能共享一個ServletContext。
    SRV.3.7 Reloading Considerations
    所有的Servlet和它們引用的類必須都處于一個類裝載器范圍內。
    SRV.3.7.1 Temporary Working Directories
    每一個ServletContext都需要一個臨時目錄,并且通過 javax.servlet.context.tempdir屬性指定。Servlet容器不需要管理這個臨時路徑的內容,但是要確保一個 ServletContext的臨時目錄對其他的ServletContext是不可見的。

    posted @ 2006-06-14 23:43 Hello Java 閱讀(1679) | 評論 (1)編輯 收藏

    動態代理和AOP的一點學習心得

         摘要: 一、最初的設計 有一個經營一家在線商店的客戶,在這個商店系統中,有一個供管理員使用的管理定單的類,代碼如下: 1 、接口 Interface OrderService{ ? ? ??????? public boolean showOrders();// 察看定單 } 2、實...  閱讀全文

    posted @ 2006-06-14 20:38 Hello Java 閱讀(661) | 評論 (1)編輯 收藏

    僅列出標題  

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 永久免费观看黄网站| 校园亚洲春色另类小说合集 | 亚洲国产精品无码专区影院| 国产亚洲欧美在线观看| 日韩精品免费一区二区三区| 中国china体内裑精亚洲日本| 毛片免费vip会员在线看| 亚洲mv国产精品mv日本mv| 国产成人yy免费视频| 亚洲精品二三区伊人久久| 在线不卡免费视频| 国产亚洲综合一区二区三区| 免费看国产一级片| 国产精品内射视频免费| 久久青青草原亚洲av无码| 国产麻豆一精品一AV一免费| 精品亚洲成a人片在线观看| 120秒男女动态视频免费| 亚洲乱码卡三乱码新区| 免费观看理论片毛片| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | a级毛片在线免费看| 亚洲视频在线观看一区| 在线永久看片免费的视频| 亚洲国产日韩a在线播放| 亚洲日韩在线中文字幕第一页 | 久久精品亚洲中文字幕无码网站 | 亚洲男女一区二区三区| 无人在线观看免费高清视频| 精品亚洲视频在线| 在线观看亚洲精品国产| 猫咪免费人成网站在线观看| 亚洲AV性色在线观看| 亚洲中文字幕在线第六区| 久久免费看黄a级毛片| 老子影院午夜伦不卡亚洲| 国产亚洲色视频在线| 91在线品视觉盛宴免费| a高清免费毛片久久| 亚洲精品视频免费看| 亚洲国产精品一区二区第一页免|