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

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

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

    隨筆-124  評論-49  文章-56  trackbacks-0
     

     

    1、 java命令和 javaw命令是怎么回事?

    我現在的理解:

    java命令在執行一個class文件的時候,

    1)首先要創建一個虛擬機實例

    2)虛擬機啟動用戶主線程 main()方法,這是非守護線程

    3)虛擬機(也可能是主線程)啟動守護線程。比如垃圾收集線程。

    4main()方法結束,并且由main()方法創建的用戶線程也結束。也就是說系統中沒有用戶線程存在了,則守護線程也結束,最后虛擬機實例自動銷毀。

    javaw命令在eclipse啟動后,也是代表了一個虛擬機實例。它一直存在應該是因為系統中有用戶線程一直在后臺運行。

    eclipse被關閉是,應該是調用了systemexist()方法,即虛擬機實例強行銷毀。

    當用戶自己編寫的class文件在eclipse中執行時,由javaw這個虛擬機實例解釋執行。

    2、 下面是網上資料總結如下:

    Java有兩種Thread:“守護線程Daemon”與“用戶線程User”。

    從字面上我們很容易將守護線程理解成是由虛擬機(virtual machine)在內部創建的,而用戶線程則是自己所創建的。事實并不是這樣,任何線程都可以是“守護線程Daemon”或“用戶線程User”。他們在幾乎每個方面都是相同的,唯一的區別是判斷虛擬機何時離開:

    用戶線程:Java虛擬機在它所有非守護線程已經離開后自動離開。

    守護線程:守護線程則是用來服務用戶線程的,如果沒有其他用戶線程在運行,那么就沒有可服務對象,也就沒有理由繼續下去。

    setDaemon(boolean on)方法可以方便的設置線程的Daemon模式,true為Daemon模式,false為User模式。setDaemon(boolean on)方法必須在線程啟動之前調用,當線程正在運行時調用會產生異常。isDaemon方法將測試該線程是否為守護線程。值得一提的是,當你在一個守護線程中產生了其他線程,那么這些新產生的線程不用設置Daemon屬性,都將是守護線程,用戶線程同樣。

    下面是演示程序:

    ----------------------------------------------------------------

    import java.io.IOException;

    /**

     * 守護線程在沒有用戶線程可服務時自動離開

     */

    public class TestMain4 extends Thread {

       

        public TestMain4() {

        }

        public void run() {

            for(int i = 1; i <= 50; i++){

                try {

                    Thread.sleep(100);

                } catch (InterruptedException ex) {

                    ex.printStackTrace();

                }

                System.out.println(i);

            }

        }

       

        public static void main(String [] args){

            TestMain4 test = new TestMain4();

            test.setDaemon(false);

            test.start();

            System.out.println("isDaemon = " + test.isDaemon());

            try {

                System.in.read(); // 接受輸入,使程序在此停頓,一旦接收到用戶輸入,main線程結束,守護線程自動結束,如果test不是守護進程必須等到test運行完了以后才退出

            } catch (Exception ex) {

                ex.printStackTrace();

            }

        }

    }

    ----------------------------------------------------------------------------------

    例:我們所熟悉的Java垃圾回收線程就是一個典型的守護線程,當我們的程序中不再有任何運行中的Thread,程序就不會再產生垃圾,垃圾回收器也就無事可做,所以當垃圾回收線程是Java虛擬機上僅剩的線程時,Java虛擬機會自動離開。

     

    3、下面是一個論壇的帖子

     

    http://topic.csdn.net/t/20060115/00/4517316.html

     

    守護線程與普通線程的唯一區別是:當JVM中所有的線程都是守護線程的時候,JVM就可以退出了;如果還有一個或以上的非守護線程則不會退出。(以上是針對正常退出,調用System.exit則必定會退出)  
        
    所以setDeamon(true)的唯一意義就是告訴JVM不需要等待它退出,讓JVM喜歡什么退出就退出吧,不用管它。

    posted @ 2010-04-25 00:06 junly 閱讀(597) | 評論 (0)編輯 收藏

    其他參考:
    1 http://gzcj.javaeye.com/blog/394648
    2 http://blog.sina.com.cn/s/blog_5f1fe33f0100d9ak.html


    類加載器
    是 Java 語言流行的重要原因之一。它使得 Java 類可以被動態加載到 Java 虛擬機中并執行。類加載器從 JDK 1.0 就出現了,最初是為了滿足 Java Applet 的需要而開發出來的。Java Applet 需要從遠程下載 Java 類文件到瀏覽器中并執行。現在類加載器在 Web 容器和 OSGi 中得到了廣泛的使用。一般來說,Java 應用的開發人員不需要直接同類加載器進行交互。Java 虛擬機默認的行為就已經足夠滿足大多數情況的需求了。不過如果遇到了需要與類加載器進行交互的情況,而對類加載器的機制又不是很了解的話,就很容易花大量的時間去調試 ClassNotFoundExceptionNoClassDefFoundError 等異常。本文將詳細介紹 Java 的類加載器,幫助讀者深刻理解 Java 語言中的這個重要概念。下面首先介紹一些相關的基本概念。

     

    類加載器基本概念

    顧名思義,類加載器(class loader)用來加載 Java 類到 Java 虛擬機中。一般來說,Java 虛擬機使用 Java 類的方式如下:Java 源程序(.java 文件)在經過 Java 編譯器編譯之后就被轉換成 Java 字節代碼(.class 文件)。類加載器負責讀取 Java 字節代碼,并轉換成 java.lang.Class 類的一個實例。每個這樣的實例用來表示一個 Java 類。通過此實例的 newInstance()方法就可以創建出該類的一個對象。實際的情況可能更加復雜,比如 Java 字節代碼可能是通過工具動態生成的,也可能是通過網絡下載的。

    基本上所有的類加載器都是 java.lang.ClassLoader 類的一個實例。下面詳細介紹這個 Java 類。

    java.lang.ClassLoader 類介紹

    java.lang.ClassLoader 類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的字節代碼,然后從這些字節代碼中定義出一個 Java 類,即 java.lang.Class 類的一個實例。除此之外,ClassLoader 還負責加載 Java 應用所需的資源,如圖像文件和配置文件等。不過本文只討論其加載類的功能。為了完成加載類的這個職責,ClassLoader 提供了一系列的方法,比較重要的方法如 表 1 所示。關于這些方法的細節會在下面進行介紹。


    表 1. ClassLoader 中與加載類相關的方法
    方法 說明
    getParent() 返回該類加載器的父類加載器。
    loadClass(String name) 加載名稱為 name 的類,返回的結果是 java.lang.Class 類的實例。
    findClass(String name) 查找名稱為 name 的類,返回的結果是 java.lang.Class 類的實例。
    findLoadedClass(String name) 查找名稱為 name 的已經被加載過的類,返回的結果是 java.lang.Class 類的實例。
    defineClass(String name, byte[] b, int off, int len) 把字節數組 b 中的內容轉換成 Java 類,返回的結果是 java.lang.Class 類的實例。這個方法被聲明為 final 的。
    resolveClass(Class<?> c) 鏈接指定的 Java 類。

    對于 表 1 中給出的方法,表示類名稱的 name 參數的值是類的二進制名稱。需要注意的是內部類的表示,如 com.example.Sample$1com.example.Sample$Inner 等表示方式。這些方法會在下面介紹類加載器的工作機制時,做進一步的說明。下面介紹類加載器的樹狀組織結構。

    類加載器的樹狀組織結構

    Java 中的類加載器大致可以分成兩類,一類是系統提供的,另外一類則是由 Java 應用開發人員編寫的。系統提供的類加載器主要有下面三個:

    • 引導類加載器(bootstrap class loader):它用來加載 Java 的核心庫,是用原生代碼來實現的,并不繼承自 java.lang.ClassLoader
    • 擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載 Java 類。
    • 系統類加載器(system class loader):它根據 Java 應用的類路徑(CLASSPATH)來加載 Java 類。一般來說,Java 應用的類都是由它來完成加載的。可以通過 ClassLoader.getSystemClassLoader() 來獲取它。

    除了系統提供的類加載器以外,開發人員可以通過繼承 java.lang.ClassLoader 類的方式實現自己的類加載器,以滿足一些特殊的需求。

    除了引導類加載器之外,所有的類加載器都有一個父類加載器。通過 表 1 中給出的 getParent() 方法可以得到。對于系統提供的類加載器來說,系統類加載器的父類加載器是擴展類加載器,而擴展類加載器的父類加載器是引導類加載器;對于開發人員編寫的類加載器來說,其父類加載器是加載此類加載器 Java 類的類加載器。因為類加載器 Java 類如同其它的 Java 類一樣,也是要由類加載器來加載的。一般來說,開發人員編寫的類加載器的父類加載器是系統類加載器。類加載器通過這種方式組織起來,形成樹狀結構。樹的根節點就是引導類加載器。圖 1 中給出了一個典型的類加載器樹狀組織結構示意圖,其中的箭頭指向的是父類加載器。


    圖 1. 類加載器樹狀組織結構示意圖
    類加載器樹狀組織結構示意圖

    代碼清單 1 演示了類加載器的樹狀組織結構。


    清單 1. 演示類加載器的樹狀組織結構
    public class ClassLoaderTree { 

    public static void main(String[] args) {
    ClassLoader loader = ClassLoaderTree.class.getClassLoader();
    while (loader != null) {
    System.out.println(loader.toString());
    loader = loader.getParent();
    }
    }
    }

    每個 Java 類都維護著一個指向定義它的類加載器的引用,通過 getClassLoader() 方法就可以獲取到此引用。代碼清單 1 中通過遞歸調用 getParent() 方法來輸出全部的父類加載器。代碼清單 1 的運行結果如 代碼清單 2 所示。


    清單 2. 演示類加載器的樹狀組織結構的運行結果
    sun.misc.Launcher$AppClassLoader@9304b1 
    sun.misc.Launcher$ExtClassLoader@190d11

    代碼清單 2 所示,第一個輸出的是 ClassLoaderTree 類的類加載器,即系統類加載器。它是 sun.misc.Launcher$AppClassLoader 類的實例;第二個輸出的是擴展類加載器,是 sun.misc.Launcher$ExtClassLoader 類的實例。需要注意的是這里并沒有輸出引導類加載器,這是由于有些 JDK 的實現對于父類加載器是引導類加載器的情況,getParent() 方法返回 null

    在了解了類加載器的樹狀組織結構之后,下面介紹類加載器的代理模式。

    類加載器的代理模式

    類加載器在嘗試自己去查找某個類的字節代碼并定義它時,會先代理給其父類加載器,由父類加載器先去嘗試加載這個類,依次類推。在介紹代理模式背后的動機之前,首先需要說明一下 Java 虛擬機是如何判定兩個 Java 類是相同的。Java 虛擬機不僅要看類的全名是否相同,還要看加載此類的類加載器是否一樣。只有兩者都相同的情況,才認為兩個類是相同的。即便是同樣的字節代碼,被不同的類加載器加載之后所得到的類,也是不同的。比如一個 Java 類 com.example.Sample,編譯之后生成了字節代碼文件 Sample.class。兩個不同的類加載器 ClassLoaderAClassLoaderB 分別讀取了這個 Sample.class 文件,并定義出兩個 java.lang.Class 類的實例來表示這個類。這兩個實例是不相同的。對于 Java 虛擬機來說,它們是不同的類。試圖對這兩個類的對象進行相互賦值,會拋出運行時異常 ClassCastException。下面通過示例來具體說明。代碼清單 3 中給出了 Java 類 com.example.Sample


    清單 3. com.example.Sample 類
    package com.example; 

    public class Sample {
    private Sample instance;

    public void setSample(Object instance) {
    this.instance = (Sample) instance;
    }
    }

    代碼清單 3 所示,com.example.Sample 類的方法 setSample 接受一個 java.lang.Object 類型的參數,并且會把該參數強制轉換成 com.example.Sample 類型。測試 Java 類是否相同的代碼如 代碼清單 4 所示。


    清單 4. 測試 Java 類是否相同
    public void testClassIdentity() { 
    String classDataRootPath = "C:\\workspace\\Classloader\\classData";
    FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath);
    FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
    String className = "com.example.Sample";
    try {
    Class<?> class1 = fscl1.loadClass(className);
    Object obj1 = class1.newInstance();
    Class<?> class2 = fscl2.loadClass(className);
    Object obj2 = class2.newInstance();
    Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class);
    setSampleMethod.invoke(obj1, obj2);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    代碼清單 4 中使用了類 FileSystemClassLoader 的兩個不同實例來分別加載類 com.example.Sample,得到了兩個不同的 java.lang.Class 的實例,接著通過 newInstance() 方法分別生成了兩個類的對象 obj1obj2,最后通過 Java 的反射 API 在對象 obj1 上調用方法 setSample,試圖把對象 obj2 賦值給 obj1 內部的 instance 對象。代碼清單 4 的運行結果如 代碼清單 5 所示。


    清單 5. 測試 Java 類是否相同的運行結果
    java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at classloader.ClassIdentity.testClassIdentity(ClassIdentity.java:26)
    at classloader.ClassIdentity.main(ClassIdentity.java:9)
    Caused by: java.lang.ClassCastException: com.example.Sample
    cannot be cast to com.example.Sample
    at com.example.Sample.setSample(Sample.java:7)
    ... 6 more

    代碼清單 5 給出的運行結果可以看到,運行時拋出了 java.lang.ClassCastException 異常。雖然兩個對象 obj1obj2 的類的名字相同,但是這兩個類是由不同的類加載器實例來加載的,因此不被 Java 虛擬機認為是相同的。

    了解了這一點之后,就可以理解代理模式的設計動機了。代理模式是為了保證 Java 核心庫的類型安全。所有 Java 應用都至少需要引用 java.lang.Object 類,也就是說在運行的時候,java.lang.Object 這個類需要被加載到 Java 虛擬機中。如果這個加載過程由 Java 應用自己的類加載器來完成的話,很可能就存在多個版本的 java.lang.Object 類,而且這些類之間是不兼容的。通過代理模式,對于 Java 核心庫的類的加載工作由引導類加載器來統一完成,保證了 Java 應用所使用的都是同一個版本的 Java 核心庫的類,是互相兼容的。

    不同的類加載器為相同名稱的類創建了額外的名稱空間。相同名稱的類可以并存在 Java 虛擬機中,只需要用不同的類加載器來加載它們即可。不同類加載器加載的類之間是不兼容的,這就相當于在 Java 虛擬機內部創建了一個個相互隔離的 Java 類空間。這種技術在許多框架中都被用到,后面會詳細介紹。

    下面具體介紹類加載器加載類的詳細過程。

    加載類的過程

    在前面介紹類加載器的代理模式的時候,提到過類加載器會首先代理給其它類加載器來嘗試加載某個類。這就意味著真正完成類的加載工作的類加載器和啟動這個加載過程的類加載器,有可能不是同一個。真正完成類的加載工作是通過調用 defineClass 來實現的;而啟動類的加載過程是通過調用 loadClass 來實現的。前者稱為一個類的定義加載器(defining loader),后者稱為初始加載器(initiating loader)。在 Java 虛擬機判斷兩個類是否相同的時候,使用的是類的定義加載器。也就是說,哪個類加載器啟動類的加載過程并不重要,重要的是最終定義這個類的加載器。兩種類加載器的關聯之處在于:一個類的定義加載器是它引用的其它類的初始加載器。如類 com.example.Outer 引用了類 com.example.Inner,則由類 com.example.Outer 的定義加載器負責啟動類 com.example.Inner 的加載過程。

    方法 loadClass() 拋出的是 java.lang.ClassNotFoundException 異常;方法 defineClass() 拋出的是 java.lang.NoClassDefFoundError 異常。

    類加載器在成功加載某個類之后,會把得到的 java.lang.Class 類的實例緩存起來。下次再請求加載該類的時候,類加載器會直接使用緩存的類的實例,而不會嘗試再次加載。也就是說,對于一個類加載器實例來說,相同全名的類只加載一次,即 loadClass 方法不會被重復調用。

    下面討論另外一種類加載器:線程上下文類加載器。

    線程上下文類加載器

    線程上下文類加載器(context class loader)是從 JDK 1.2 開始引入的。類 java.lang.Thread 中的方法 getContextClassLoader()setContextClassLoader(ClassLoader cl) 用來獲取和設置線程的上下文類加載器。如果沒有通過 setContextClassLoader(ClassLoader cl) 方法進行設置的話,線程將繼承其父線程的上下文類加載器。Java 應用運行的初始線程的上下文類加載器是系統類加載器。在線程中運行的代碼可以通過此類加載器來加載類和資源。

    前面提到的類加載器的代理模式并不能解決 Java 應用開發中會遇到的類加載器的全部問題。Java 提供了很多服務提供者接口(Service Provider Interface,SPI),允許第三方為這些接口提供實現。常見的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。這些 SPI 的接口由 Java 核心庫來提供,如 JAXP 的 SPI 接口定義包含在 javax.xml.parsers 包中。這些 SPI 的實現代碼很可能是作為 Java 應用所依賴的 jar 包被包含進來,可以通過類路徑(CLASSPATH)來找到,如實現了 JAXP SPI 的 Apache Xerces 所包含的 jar 包。SPI 接口中的代碼經常需要加載具體的實現類。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory 類中的 newInstance() 方法用來生成一個新的 DocumentBuilderFactory 的實例。這里的實例的真正的類是繼承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的實現所提供的。如在 Apache Xerces 中,實現的類是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而問題在于,SPI 的接口是 Java 核心庫的一部分,是由引導類加載器來加載的;SPI 實現的 Java 類一般是由系統類加載器來加載的。引導類加載器是無法找到 SPI 的實現類的,因為它只加載 Java 的核心庫。它也不能代理給系統類加載器,因為它是系統類加載器的祖先類加載器。也就是說,類加載器的代理模式無法解決這個問題。

    線程上下文類加載器正好解決了這個問題。如果不做任何的設置,Java 應用的線程的上下文類加載器默認就是系統上下文類加載器。在 SPI 接口的代碼中使用線程上下文類加載器,就可以成功的加載到 SPI 實現的類。線程上下文類加載器在很多 SPI 的實現中都會用到。

    下面介紹另外一種加載類的方法:Class.forName

    Class.forName

    Class.forName 是一個靜態方法,同樣可以用來加載類。該方法有兩種形式:Class.forName(String name, boolean initialize, ClassLoader loader)Class.forName(String className)。第一種形式的參數 name 表示的是類的全名;initialize 表示是否初始化類;loader 表示加載時使用的類加載器。第二種形式則相當于設置了參數 initialize 的值為 trueloader 的值為當前類的類加載器。Class.forName 的一個很常見的用法是在加載數據庫驅動的時候。如 Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance() 用來加載 Apache Derby 數據庫的驅動。

    在介紹完類加載器相關的基本概念之后,下面介紹如何開發自己的類加載器。


    開發自己的類加載器

    雖然在絕大多數情況下,系統默認提供的類加載器實現已經可以滿足需求。但是在某些情況下,您還是需要為應用開發出自己的類加載器。比如您的應用通過網絡來傳輸 Java 類的字節代碼,為了保證安全性,這些字節代碼經過了加密處理。這個時候您就需要自己的類加載器來從某個網絡地址上讀取加密后的字節代碼,接著進行解密和驗證,最后定義出要在 Java 虛擬機中運行的類來。下面將通過兩個具體的實例來說明類加載器的開發。

    文件系統類加載器

    第一個類加載器用來加載存儲在文件系統上的 Java 字節代碼。完整的實現如 代碼清單 6 所示。


    清單 6. 文件系統類加載器
    public class FileSystemClassLoader extends ClassLoader { 

    private String rootDir;

    public FileSystemClassLoader(String rootDir) {
    this.rootDir = rootDir;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
    byte[] classData = getClassData(name);
    if (classData == null) {
    throw new ClassNotFoundException();
    }
    else {
    return defineClass(name, classData, 0, classData.length);
    }
    }

    private byte[] getClassData(String className) {
    String path = classNameToPath(className);
    try {
    InputStream ins = new FileInputStream(path);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int bufferSize = 4096;
    byte[] buffer = new byte[bufferSize];
    int bytesNumRead = 0;
    while ((bytesNumRead = ins.read(buffer)) != -1) {
    baos.write(buffer, 0, bytesNumRead);
    }
    return baos.toByteArray();
    } catch (IOException e) {
    e.printStackTrace();
    }
    return null;
    }

    private String classNameToPath(String className) {
    return rootDir + File.separatorChar
    + className.replace('.', File.separatorChar) + ".class";
    }
    }

    代碼清單 6 所示,類 FileSystemClassLoader 繼承自類 java.lang.ClassLoader。在 表 1 中列出的 java.lang.ClassLoader 類的常用方法中,一般來說,自己開發的類加載器只需要覆寫 findClass(String name) 方法即可。java.lang.ClassLoader 類的方法 loadClass() 封裝了前面提到的代理模式的實現。該方法會首先調用 findLoadedClass() 方法來檢查該類是否已經被加載過;如果沒有加載過的話,會調用父類加載器的 loadClass() 方法來嘗試加載該類;如果父類加載器無法加載該類的話,就調用 findClass() 方法來查找該類。因此,為了保證類加載器都正確實現代理模式,在開發自己的類加載器時,最好不要覆寫 loadClass() 方法,而是覆寫 findClass() 方法。

    FileSystemClassLoaderfindClass() 方法首先根據類的全名在硬盤上查找類的字節代碼文件(.class 文件),然后讀取該文件內容,最后通過 defineClass() 方法來把這些字節代碼轉換成 java.lang.Class 類的實例。

    網絡類加載器

    下面將通過一個網絡類加載器來說明如何通過類加載器來實現組件的動態更新。即基本的場景是:Java 字節代碼(.class)文件存放在服務器上,客戶端通過網絡的方式獲取字節代碼并執行。當有版本更新的時候,只需要替換掉服務器上保存的文件即可。通過類加載器可以比較簡單的實現這種需求。

    NetworkClassLoader 負責通過網絡下載 Java 類字節代碼并定義出 Java 類。它的實現與 FileSystemClassLoader 類似。在通過 NetworkClassLoader 加載了某個版本的類之后,一般有兩種做法來使用它。第一種做法是使用 Java 反射 API。另外一種做法是使用接口。需要注意的是,并不能直接在客戶端代碼中引用從服務器上下載的類,因為客戶端代碼的類加載器找不到這些類。使用 Java 反射 API 可以直接調用 Java 類的方法。而使用接口的做法則是把接口的類放在客戶端中,從服務器上加載實現此接口的不同版本的類。在客戶端通過相同的接口來使用這些實現類。網絡類加載器的具體代碼見 下載

    在介紹完如何開發自己的類加載器之后,下面說明類加載器和 Web 容器的關系。


    類加載器與 Web 容器

    對于運行在 Java EE™ 容器中的 Web 應用來說,類加載器的實現方式與一般的 Java 應用有所不同。不同的 Web 容器的實現方式也會有所不同。以 Apache Tomcat 來說,每個 Web 應用都有一個對應的類加載器實例。該類加載器也使用代理模式,所不同的是它是首先嘗試去加載某個類,如果找不到再代理給父類加載器。這與一般類加載器的順序是相反的。這是 Java Servlet 規范中的推薦做法,其目的是使得 Web 應用自己的類的優先級高于 Web 容器提供的類。這種代理模式的一個例外是:Java 核心庫的類是不在查找范圍之內的。這也是為了保證 Java 核心庫的類型安全。

    絕大多數情況下,Web 應用的開發人員不需要考慮與類加載器相關的細節。下面給出幾條簡單的原則:

    • 每個 Web 應用自己的 Java 類文件和使用的庫的 jar 包,分別放在 WEB-INF/classesWEB-INF/lib 目錄下面。
    • 多個應用共享的 Java 類文件和 jar 包,分別放在 Web 容器指定的由所有 Web 應用共享的目錄下面。
    • 當出現找不到類的錯誤時,檢查當前類的類加載器和當前線程的上下文類加載器是否正確。

    在介紹完類加載器與 Web 容器的關系之后,下面介紹它與 OSGi 的關系。

    類加載器與 OSGi

    OSGi™ 是 Java 上的動態模塊系統。它為開發人員提供了面向服務和基于組件的運行環境,并提供標準的方式用來管理軟件的生命周期。OSGi 已經被實現和部署在很多產品上,在開源社區也得到了廣泛的支持。Eclipse 就是基于 OSGi 技術來構建的。

    OSGi 中的每個模塊(bundle)都包含 Java 包和類。模塊可以聲明它所依賴的需要導入(import)的其它模塊的 Java 包和類(通過 Import-Package),也可以聲明導出(export)自己的包和類,供其它模塊使用(通過 Export-Package)。也就是說需要能夠隱藏和共享一個模塊中的某些 Java 包和類。這是通過 OSGi 特有的類加載器機制來實現的。OSGi 中的每個模塊都有對應的一個類加載器。它負責加載模塊自己包含的 Java 包和類。當它需要加載 Java 核心庫的類時(以 java 開頭的包和類),它會代理給父類加載器(通常是啟動類加載器)來完成。當它需要加載所導入的 Java 類時,它會代理給導出此 Java 類的模塊來完成加載。模塊也可以顯式的聲明某些 Java 包和類,必須由父類加載器來加載。只需要設置系統屬性 org.osgi.framework.bootdelegation 的值即可。

    假設有兩個模塊 bundleA 和 bundleB,它們都有自己對應的類加載器 classLoaderA 和 classLoaderB。在 bundleA 中包含類 com.bundleA.Sample,并且該類被聲明為導出的,也就是說可以被其它模塊所使用的。bundleB 聲明了導入 bundleA 提供的類 com.bundleA.Sample,并包含一個類 com.bundleB.NewSample 繼承自 com.bundleA.Sample。在 bundleB 啟動的時候,其類加載器 classLoaderB 需要加載類 com.bundleB.NewSample,進而需要加載類 com.bundleA.Sample。由于 bundleB 聲明了類 com.bundleA.Sample 是導入的,classLoaderB 把加載類 com.bundleA.Sample 的工作代理給導出該類的 bundleA 的類加載器 classLoaderA。classLoaderA 在其模塊內部查找類 com.bundleA.Sample 并定義它,所得到的類 com.bundleA.Sample 實例就可以被所有聲明導入了此類的模塊使用。對于以 java 開頭的類,都是由父類加載器來加載的。如果聲明了系統屬性 org.osgi.framework.bootdelegation=com.example.core.*,那么對于包 com.example.core 中的類,都是由父類加載器來完成的。

    OSGi 模塊的這種類加載器結構,使得一個類的不同版本可以共存在 Java 虛擬機中,帶來了很大的靈活性。不過它的這種不同,也會給開發人員帶來一些麻煩,尤其當模塊需要使用第三方提供的庫的時候。下面提供幾條比較好的建議:

    • 如果一個類庫只有一個模塊使用,把該類庫的 jar 包放在模塊中,在 Bundle-ClassPath 中指明即可。
    • 如果一個類庫被多個模塊共用,可以為這個類庫單獨的創建一個模塊,把其它模塊需要用到的 Java 包聲明為導出的。其它模塊聲明導入這些類。
    • 如果類庫提供了 SPI 接口,并且利用線程上下文類加載器來加載 SPI 實現的 Java 類,有可能會找不到 Java 類。如果出現了 NoClassDefFoundError 異常,首先檢查當前線程的上下文類加載器是否正確。通過 Thread.currentThread().getContextClassLoader() 就可以得到該類加載器。該類加載器應該是該模塊對應的類加載器。如果不是的話,可以首先通過 class.getClassLoader() 來得到模塊對應的類加載器,再通過 Thread.currentThread().setContextClassLoader() 來設置當前線程的上下文類加載器。

    總結

    類加載器是 Java 語言的一個創新。它使得動態安裝和更新軟件組件成為可能。本文詳細介紹了類加載器的相關話題,包括基本概念、代理模式、線程上下文類加載器、與 Web 容器和 OSGi 的關系等。開發人員在遇到 ClassNotFoundExceptionNoClassDefFoundError 等異常的時候,應該檢查拋出異常的類的類加載器和當前線程的上下文類加載器,從中可以發現問題的所在。在開發自己的類加載器的時候,需要注意與已有的類加載器組織結構的協調。

    posted @ 2010-04-24 22:26 junly 閱讀(602) | 評論 (0)編輯 收藏


    來自:http://www.pussor.com/?p=3

    官網:http://www.pushlets.com/

    Ajax等Web 2.0技術的廣泛應用,推動了C/S向B/S的轉變,如今很多應用如監控、即時通信等系統都需要實時同步服務器端和客戶端的數據更新。Comet在這種需求下應運而生,本文簡單介紹了基于Comet的開源框架Pushlet。

    Comet基礎

    Comet 是一個用于描述客戶端和服務器之間的交互的術語,即使用長期保持的 HTTP 連接來在連接保持暢通的情況下支持客戶端和服務器間的事件驅動的通信。

    —引用自“Comet的誘惑”

    傳統的web系統的工作流程是客戶端發出請求,服務器端進行響應,而Comet則是在現有技術的基礎上,實現服務器數據、事件等快速PUSH到客戶端,所以會出現一個術語”服務器推“技術。

    PUSH實現方式

    JSP/SERVLET PUSH

    原理:

    利用JSP/SERVEL技術,在不關閉HTTP流的情況下PUSH數據到客戶端瀏覽器;

    實現:

    基于 AJAX 的長輪詢(long-polling)方式

    AJAX 的出現使得 JavaScript 可以調用 XMLHttpRequest 對象發出 HTTP 請求,JavaScript 響應處理函數根據服務器返回的信息對 HTML 頁面的顯示進行更新。使用 AJAX 實現“服務器推”與傳統的 AJAX 應用不同之處在于:

    1. 服務器端會阻塞請求直到有數據傳遞或超時才返回。
    2. 客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息后,再次發出請求,重新建立連接。
    3. 當客戶端處理接收的數據、重新建立連接時,服務器端可能有新的數據到達;這些信息會被服務器端保存直到客戶端重 新建立連接,客戶端會一次把當前服務器端所有的信息取回。

    Pushlet實例

    以Pushlet中的ping案例來進行分析:

    1. 新建一個Web項目取名ping,并導入Pushlet的jar包;
    2. 在src目錄下配置sources.properties、pushlet.properties文件;
    3. webroot目錄下導入js-pushlet-client.js,js-pushlet-net.html;
    4. 新建TestEventPullSources.java;
    5. 新建index.html,引入js-pushlet-client.js;
    6. 新建pingok.jsp;
    7. 修改web.xml加上pushlet的servlet
    8. 打包、部署ping項目;



    實例1            Pushlet CookBook部分翻譯 + 注釋

    pushlet 2.0.3 源碼分析(服務器端)

    posted @ 2010-04-23 13:38 junly 閱讀(6180) | 評論 (1)編輯 收藏
     PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域,這塊內存主要是存放Class和Meta信息的,Class在被Loader時就會被放到PermGen space中,它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,所以如果APP會LOAD很多CLASS的話,就很可能出現PermGen space錯誤,這種錯誤常見在web服務器對JSP進行pre compile的時候。

     在tomcat中redeploy時出現outofmemory的錯誤. 可以有以下幾個方面的原因:
     1, 使用了proxool,因為proxool內部包含了一個老版本的cglib.
     2, log4j,最好不用,只用common-logging
     3, 老版本的cglib,快點更新到最新版。
     4, 更新到最新的hibernate3.2 3、

     這里以tomcat環境為例,其它WEB服務器如jboss,weblogic等是同一個道理。

     一、java.lang.OutOfMemoryError: PermGen space PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域, 這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGen space中, 它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對 PermGen space進行清理,所以如果你的應用中有很多CLASS的話,就很可能出現PermGen space錯誤, 這種錯誤常見在web服務器對JSP進行pre compile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息了。

     解決方法: 手動設置MaxPermSize大小修改TOMCAT_HOME/bin/catalina.sh 在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m

     建議:將相同的第三方jar文件移置到tomcat/shared/lib目錄下,這樣可以達到減少jar 文檔重復占用內存的目的。


     二、java.lang.OutOfMemoryError: Java heap space Heap size 設置 JVM堆的設置是指java程序運行過程中JVM可以調配使用的內存空間的設置.JVM在啟動的時候會自動設置Heap size的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。提示:在JVM中如果98%的時間是用于GC且可用的Heap size 不足2%的時候將拋出此異常信息。提示:Heap Size 最大不要超過可用物理內存的80%,一般的要將-Xms和-Xmx選項設置為相同,而-Xmn為1/4的-Xmx值。

     解決方法:手動設置Heap size 修改TOMCAT_HOME/bin/catalina.sh 在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"


     三、實例,以下給出1G內存環境下java jvm 的參數設置參考:
    JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "

     

    內存不足 (OutOfMemory) - 由于java 堆或本地內存中的內存耗盡,應用程序顯示“內存不足”錯誤。
    內存泄漏-java 堆或本地內存的持續內存增長,最終將導致內存不足狀態。
    調試內存泄漏狀態的技術與調試內存不足狀態的技術相同。

    Java 堆 - 這是 JVM 用來分配 java 對象的內存。
    如果JVM不能在java堆中獲得更多內存來分配更多java對象,將會拋出java內存不足(java.lang.OutOfMemoryError)錯誤。默認情況下,應用程序崩潰。
    本地內存 - 這是 JVM 用于其內部操作的內存。
    如果 JVM 無法獲得更多本地內存,它將拋出本地內存不足(本地 OutOfMemoryError)錯誤。當進程到達操作系統的進程大小限值,或者當計算機用完 RAM 和交換空間時,通常會發生這種情況。
    進程大小 - 進程大小將是 java 堆、本地內存與加載的可執行文件和庫所占用內存的總和。在 32 位操作系統上,進程的虛擬地址空間最大可達到 4 GB。從這 4 GB 內存中,操作系統內核為自己保留一部分內存(通常為 1 - 2 GB)。剩余內存可用于應用程序。


    2.
    java虛擬機是遵照有關規范的一個軟件實現,存在于內存中。jvm是由安裝于機器上的jre(java運行環境)生成的。通常來說,每次運行一個application都會生成一個jvm,但是也可以有多個程序在同一個jvm里面。

    可以使用命令java -X查看非標準(non-standard)的程序運行選項,以下3個是我所關心的:

    -Xms        set initial Java heap size
    -Xmx        set maximum Java heap size
    -Xss        set java thread stack size

    -Xmx設置應用程序(不是jvm)能夠使用的最大內存數,這個值也不應該設置過大,超過機器內存。
    例如:java -Xmx50M testMemory
    -Xms設置程序初始化的時候內存棧的大小。有時可以用于改變程序運行的效率。
    例如使用以下方式運行一個占用20M左右內存的程序testMemory:
          java -Xms50M testMemory

    使用這個方法可以得到應用的空間使用量

    /*
    Returns the total amount of memory in the Java virtual machine. The value returned by this method may vary over time, depending on the host environment.
    */

    System.out.println(Runtime.getRuntime().totalMemory());


    3.
    查看java進程的內存使用量:
    Windows任務管理器(Windows Task Manager)

    增大運行應用的Heap的取值

    //命令行執行方式
    java -Xms256 -Xmx512m app

    //Tomcat執行方式
    Windows下,在文件{tomcat_home}/bin/catalina.bat

    在文件開頭可增加如下設置:

    set JAVA_OPTS=-Xms256m -Xmx512m

    Unix下,在文件{tomcat_home}/bin/catalina.sh的前面,可增加如下設置:

    JAVA_OPTS='-Xms256m -Xmx512m'

    posted @ 2010-04-22 10:18 junly 閱讀(322) | 評論 (0)編輯 收藏
         摘要: <c3p0-config>    <default-config>  <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->  <property name="acquireIncrement">3</property&g...  閱讀全文
    posted @ 2010-04-20 09:20 junly 閱讀(856) | 評論 (0)編輯 收藏

    1 配置Action的struts.xml ??????

    <struts>
        
    <!-- Struts 2的Action都必須配置在package里-->
        
    <package name="default" extends="struts-default">
    <!-- 定義一個Logon的Action實現類為lee.Logon -->
    <action name="Logon" class="lee.Logon">
    <!--配置Action返回input時轉入/pages/Logon.jsp頁面-->
    <result name="input">/pages/Logon.jsp</result>
    <!--配置Action返回cancel時重定向到Welcome的Action-->
    <result name="cancel" type="redirect-action">Welcome</result>
    <!--配置Action返回success時重定向到MainMenu的Action -->
    <result type="redirect-action">MainMenu</result>
    <!--配置Action返回expired時進入ChangePassword的Action連-->
    <result name="expired" type="chain">ChangePassword</result>
    </action>
    <!--定義Logoff的Action實現類為lee.Logoff -->
    <action name="Logoff" class=" lee.Logoff">
    <!--配置Action返回success重定向到MainMenu的Action -->
    <result type="redirect-action">Welcome</result>
    </action>
    </package>
    </struts>
    2 配置Struts 2 全局屬性的struts.properties ??????
    #指定Struts 2處于開發狀態 ????????????
    struts.devMode = false
    #指定當Struts 2配置文件改變后,Web框架是否重新加載Struts 2配置文件 ????????
    struts.configuration.xml.reload=true
    3 編輯Web 應用的web.xml配置文件,配置Struts 2 的核心Filter??
    <?xml version="1.0" encoding="GBK"?>
    <!-- web-app是Web應用配置文件的根元素,提定Web應用的Schema信息-->
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation
    ="http://java.sun.com/xml/ns/j2ee http://java.sun.
    com/xml/ns/j2ee/web-app_2_4.xsd"
    >
    <!--定義Struts 2的FilterDispatcher的Filter -->
    <filter>
    <!-- 定義核心Filter的名字-->
    <filter-name>struts2</filter-name>
    <!--典定義核心Filter的實現類 -->
    <filter-class>org.apache.Struts2.dispatcher.FilterDispatcher
    </ filter-class>
    <init-param>
    <!--配置Struts 2框架默認加載的Action包結構-->
    <param-name>actionPackages</param-name>
    <param-value>org.apache.struts2.showcase.person</param-value>
    </init-param>
    <!--配置Struts 2框架的配置提共者類-->
    <init-param>
    <param-name>configProviders </param-name>
    <param-value>lee.MyConfigurationProvider</param-value>
    </init-param>
    </filter>
    <!-- FilterDispatcher用來初始化Struts 2并且處理所有的Web請求-->
    <filter-mapping>
    <filter-name>Struts2</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>
    三個有特殊意義的初始化參數:
    (1) config:參數值是以(,)號隔開的字符串,每個字符串都是一個xml配置文件的位置。Struts2框架將自動加載這些配置文件。
    (2) actionPackages:參數值是以(,)號隔開的字符串,每個字符串都是一個包空間,Struts2框架將掃描這些包空間下的Action類。
    (3) configProviders:如果用戶需要實現自已的ConfigurationProvider類,用戶可以提供一個或多個實現了ConfigurationProvider接口的類,然后將這些類的類名設置成該屬性的值,多個類名這間以(,)隔開。
    (4) 還可以在些配置常量,其中<param-name>子元素指定常量name,而<param-value>指定常量value.

    4 在web.xml文件中配置加載Struts 2標簽庫
    <!--手動配置Struts 2的標簽庫-->
    <taglib>
    <!--配置Struts 2標簽庫的URI -->
    <taglib-uri>/s</taglib-uri>
    <!--指定Struts 2標簽庫定義文件的位置-->
    <taglib-location>/WEB-INF/struts-tags.tld</taglib-location>
    </taglib>
    注意:Servlet2.4以上的規范,無需在web.xml文件中配置標簽庫定義,因為Servlet2.4規范會自動加載該標簽庫文件。
    5 文件結構
    Struts2qs
    |-WEB-INF
    |         |-classes(struts.xml)
    |         |-lib(commons-logging.jar??freemarker.jar??ognl.jar??struts2-core.jar??xwork.jar)
    |         |-web.xml
    |-login.jsp

    6 將struts.xml配置文件分解成多個配置文件,模塊化管理
    <?xml version="1.0" encoding="UTF-8" ?>
    <!-- 指定Struts 2 配置文件的DTD信息-->
    <!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"
    >
    <!--下面是Struts 2配置文件的根元素-->
    <struts>
    <!--通過include元素導入其他配置文件-->
    <include file="struts-part1.xml" />

    </struts>

    7 包空間的繼承
    <!--指定Struts 2 配置文件的根元素 -->
    <struts>
    <!-- 配置名為lee的包空間,繼承struts-default包空間-->
    <package name="lee" extends="struts-default">

    </package>
    </struts>
    8 可插拔的方式來安裝插件
    配置struts2與spring框架,只要將struts2-spring-plugin2.06.jar文件放在WEB-INF/lib路徑下,Struts2框架將自動加載該文件
    posted @ 2010-03-05 10:24 junly 閱讀(328) | 評論 (0)編輯 收藏

    方法一:
     conf/server.xml文件
     Context path中間加上reloadable="true"
     例如:<Context path="" docBase=""  reloadable="true">

    方法二:
     刪除work目錄下的緩存文件
     可以把Catalina目錄刪除;
     
     注意:不能把work整個目錄刪除,不然重啟tomcat時,會把conf/web.xml刪除掉,這樣在啟動時,日志會提示:No Default web.xml,且訪問頁面會顯示404錯誤;

    posted @ 2010-02-28 15:22 junly 閱讀(887) | 評論 (0)編輯 收藏

    什么是JNDI?為什么使用JNDI?

    JNDI是Java 命名與目錄接口(Java Naming and Directory Interface)

    要了解JNDI的作用,我們可以從“如果不用JNDI我們怎樣做?用了JNDI后我們又將怎樣做?”這個問題來探討。

    沒有JNDI的做法:
    程序員開發時,知道要開發訪問MySQL數據庫的應用,于是將一個對 MySQL JDBC 驅動程序類的引用進行了編碼,并通過使用適當的 JDBC URL 連接到數據庫。
    就像以下代碼這樣:

    Connection conn=null;
    try {
       Class.forName("com.mysql.jdbc.Driver",true, Thread.currentThread().getContextClassLoader());        conn=DriverManager.getConnection("jdbc:mysql://MyDBServer?user=qingfeng&password=mingyue");  /* 使用conn并進行SQL操作 */     conn.close();
    } catch(Exception e) {
       e.printStackTrace();
    } finally {
       if(conn!=null) {
        try {       conn.close();   
        } catch(SQLException e) {
        }
    }}
    這是傳統的做法,這種做法一般在小規模的開發過程中不會產生問題,只要程序員熟悉Java語言、了解JDBC技術和MySQL,可以很快開發出相應的應用程序。

    沒有JNDI的做法存在的問題:
    1、數據庫服務器名稱MyDBServer 、用戶名和口令都可能需要改變,由此引發JDBC URL需要修改;
    2、數據庫可能改用別的產品,如改用DB2或者Oracle,引發JDBC驅動程序包和類名需要修改;
    3、隨著實際使用終端的增加,原配置的連接池參數可能需要調整;
    4、......

    解決辦法:
    程序員應該不需要關心“具體的數據庫后臺是什么?JDBC驅動程序是什么?JDBC URL格式是什么?訪問數據庫的用戶名和口令是什么?”等等這些問題,程序員編寫的程序應該沒有對 JDBC 驅動程序的引用,沒有服務器名稱,沒有用戶名稱或口令 —— 甚至沒有數據庫池或連接管理。而是把這些問題交給J2EE容器來配置和管理,程序員只需要對這些配置和管理進行引用即可。

    由此,就有了JNDI。

    用了JNDI之后的做法:
    首先,在在J2EE容器中配置JNDI參數,定義一個數據源,也就是JDBC引用參數,給這個數據源設置一個名稱;然后,在程序中,通過數據源名稱引用數據源從而訪問后臺數據庫。
    具體操作如下(以JBoss為例):
    1、配置數據源
    在JBoss的 D:\jboss420GA\docs\examples\jca 文件夾下面,有很多不同數據庫引用的數據源定義模板。將其中的 mysql-ds.xml 文件Copy到你使用的服務器下,如 D:\jboss420GA\server\default\deploy。
    修改 mysql-ds.xml 文件的內容,使之能通過JDBC正確訪問你的MySQL數據庫,如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
    <local-tx-datasource>
        <jndi-name>MySqlDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/lw</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>root</user-name>
        <password>rootpassword</password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
        <metadata>
           <type-mapping>mySQL</type-mapping>
        </metadata>
    </local-tx-datasource>
    </datasources>

    這里,定義了一個名為MySqlDS的數據源,其參數包括JDBC的URL,驅動類名,用戶名及密碼等。

    2、在程序中引用數據源:

    Connection conn=null;
    try { 
    Context ctx=new InitialContext();
    Object datasourceRef=ctx.lookup("java:MySqlDS"); //引用數據源 
    DataSource ds=(Datasource)datasourceRef;  conn=ds.getConnection();  /* 使用conn進行數據庫SQL操作 */
    ...... 
    c.close();
    } catch(Exception e) { 
    e.printStackTrace();
    } finally {  if(conn!=null) {   
     try {    
     conn.close();   
     } catch(SQLException e) { }  }}
    直接使用JDBC或者通過JNDI引用數據源的編程代碼量相差無幾,但是現在的程序可以不用關心具體JDBC參數了。
    在系統部署后,如果數據庫的相關參數變更,只需要重新配置 mysql-ds.xml 修改其中的JDBC參數,只要保證數據源的名稱不變,那么程序源代碼就無需修改。

    由此可見,JNDI避免了程序與數據庫之間的緊耦合,使應用更加易于配置、易于部署。

    所以,在J2EE規范中,J2EE 中的資源并不局限于 JDBC 數據源。引用的類型有很多,其中包括資源引用(已經討論過)、環境實體和 EJB 引用。特別是 EJB 引用,它暴露了 JNDI 在 J2EE 中的另外一項關鍵角色:查找其他應用程序組件。

     

    JNDI原理

    sun只是提供了JNDI的接口(即規范),IBM, Novell, Sun 和 WebLogic 和JBOSS已經為 JNDI 提供了服務提供程序,

    在JNDI中,在目錄結構中的每一個結點稱為context。每一個JNDI名字都是相對于context的。這里沒有絕對名字的概念存在。對一個應用來說,它可以通過使用 InitialContext 類來得到其第一個context: 

        Context ctx = new InitialContext();

        ctx.bind("name", Object);

        ctx.lookup("name");

    Context:上下文,我的理解是相當與文件系統的中的目錄(JNDI的Naming Service是可以用操作系統的文件系統的,哈哈).

    entry/object:一個節點,相當與文件系統中的目錄或文件.

    filter:查詢/過濾條件是一個字符串表達式如:(&(objectClass=top)(cn=*))查詢出objectClass屬性為top,cn屬性為所有情況的entry.

    Attribute:entry/object的屬性可以理解成JAVA對象的屬性,不同的是這個屬性可以多次賦值.

    A.將接口分為Context 和 DirContext  

       JNDI有兩個核心接口Context和DirContext,Context中包含 了基本的名字操作,而DirContext則將這些操作擴展到目錄服務。DirContext 對Context進行了擴展,提供了基本的目錄服務操作, 對名字對象屬性的維護、基于屬性的名字查找等等。  

    B.上下文列表的多種方法  

       一般來說有兩種進行上下文列表的應用:上下文瀏覽應用和對上下文中的對象進行實際操作的應用。  

       上下文瀏覽應用一般只需要顯示上下文中包含內容的名字,或者再獲取一些諸如對象的類型之類的信息。這種類型的應用一般都是交互式的,可以允許用戶在列舉的上下文列表中選擇一些進行進一步的顯示。  

       另外有一些應用需要對上下文中的對象進行實際的操作,比如,一個備份程序需要對目錄中所有文件的狀態進行操作,或者某打印機管理員可能需要對大樓中的所有打印機進行復位。為了進行這樣的操作,程序需要獲取上下文中的實際對象。  

       對于這樣兩種類型的應用,Context接口提供了兩種上下文列表方法list()和 listBindings()。其中list()只返回一系列名字/類映射,而listBindings() 則返回名字、類和對象本身。顯然 list()用于上下文瀏覽應用而listBindings()用于那些需要對對象進行實際操作的應用。  
    例:
    =================將以下代碼段添加到server.xml中的<Host>中============
    <!-- configure DataSource. Add the following code into server.xml -->

    <Context path="/bookstore" docBase="bookstore" debug="0"
    reloadable="true" >

    <!-- 數據源名稱 -->
    <Resource name="jdbc/BookDB"
                   auth="Container"
                   type="javax.sql.DataSource" />

    <ResourceParams name="jdbc/BookDB">
        <parameter>
          <name>factory</name>
          <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
        </parameter>

        <!-- Maximum number of dB connections in pool. Make sure you
             configure your mysqld max_connections large enough to handle
             all of your db connections. Set to 0 for no limit.
             -->
    <!-- 活動狀態最大連接數 -->
        <parameter>
          <name>maxActive</name>
          <value>100</value>
        </parameter>

        <!-- Maximum number of idle dB connections to retain in pool.
             Set to 0 for no limit.
             -->
    <!-- 空閑狀態數據庫連接最大數 -->
        <parameter>
          <name>maxIdle</name>
          <value>30</value>
        </parameter>

        <!-- Maximum time to wait for a dB connection to become available
             in ms, in this example 10 seconds. An Exception is thrown if
             this timeout is exceeded. Set to -1 to wait indefinitely.
            Maximum time to wait for a dB connection to become available
             in ms, in this example 10 seconds. An Exception is thrown if
             this timeout is exceeded. Set to -1 to wait indefinitely.
             -->
    <!-- 數據庫處于空閑狀態的最長時間 -->
        <parameter>
          <name>maxWait</name>
          <value>10000</value>
        </parameter>

        <!-- MySQL dB username and password for dB connections -->
    <!-- 指定連接數據庫的用戶名及密碼 -->
        <parameter>
         <name>username</name>
         <value>dbuser</value>
        </parameter>
        <parameter>
         <name>password</name>
         <value>1234</value>
        </parameter>

        <!-- Class name for mm.mysql JDBC driver -->
    <!-- 指定JDBC驅動 -->
        <parameter>
           <name>driverClassName</name>
           <value>com.mysql.jdbc.Driver</value>
        </parameter>

        <!-- The JDBC connection url for connecting to your MySQL dB.
             The autoReconnect=true argument to the url makes sure that the
             mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
             connection. mysqld by default closes idle connections after 8 hours.
             -->
    <!-- 指定連接數據庫的URL -->
        <parameter>
          <name>url</name>
          <value>jdbc:mysql://localhost:3306/BookDB?autoReconnect=true</value>
        </parameter>
    </ResourceParams>

    </Context> 
    運行機制:
    1、 首先程序代碼獲取初始化的 JNDI 環境并且調用 Context.lookup() 方法從 JNDI 服務提供者那里獲一個 DataSource 對象

    2、 中間層 JNDI 服務提供者返回一個 DataSource 對象給當前的 Java 應用程序這個 DataSource 對象代表了中間層服務上現存的緩沖數據源

    3、 應用程序調用 DataSource 對象的 getConnection() 方法

    4、 當 DataSource 對象的 getConnection() 方法被調用時,中間層服務器將查詢數據庫 連接緩沖池中有沒有 PooledConnection 接口的實例對象。這個 PooledConnection 對象將被用于與數據庫建立物理上的數據庫連接

    5、 如果在緩沖池中命中了一個 PooledCoonection 對象那么連接緩沖池將簡單地更 新內部的緩沖連接隊列并將該 PooledConnection 對象返回。如果在緩沖池內沒 有找到現成的 PooledConnection 對象,那么 ConnectionPoolDataSource 接口將會被 用來產生一個新的 PooledConnection 對象并將它返回以便應用程序使用

    6。 中間層服務器調用 PooledConnection 對象的 getConnection() 方法以便返還一個 java.sql.Connection 對象給當前的 Java 應用程序

    7、 當中間層服務器調用 PooledConnection 對象的 getConnection() 方法時, JDBC 數據 庫驅動程序將會創建一個 Connection 對象并且把它返回中間層服務器

    8、 中間層服務器將 Connection 對象返回給應用程序 Java 應用程序,可以認為這個 Connection 對象是一個普通的 JDBC Connection 對象使用它可以和數據庫建立。事 實上的連接與數據庫引擎產生交互操作 。

    9、 當應用程序不需要使用 Connection 對象時,可以調用 Connection 接口的 close() 方 法。請注意這種情況下 close() 方法并沒有關閉事實上的數據庫連接,僅僅是釋 放了被應用程序占用的數據庫連接,并將它還給數據庫連接緩沖池,數據庫連接 緩沖池會自動將這個數據庫連接交給請求隊列中下一個的應用程序使用。

    posted @ 2010-02-23 10:36 junly 閱讀(1367) | 評論 (0)編輯 收藏

    JDBC-ODBC橋連接數據庫

    不足:需要在客戶端安裝ODBC驅動程序,ODBC驅動程序還需要具有客戶端的控制權限。
    方法:
    1.創建數據源
    2.裝載驅動并與DBMS建立連接
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");     
    Connection con=DriverManager.getConnectio("jdbc:odbc:jia","sa","123");
    3.查詢   
    Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
    ResultSet rs = stmt.executeQuery(sql);   
    4.更新   
    Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);         
    if(stmt.executeUpdate(sql)<=0){return false;}   
    else{return true;}      
    5.讀取數據
    Statement 接口提供了3種執行SQL語句的方法:
    qexecuteQuery()
    qexecuteUpdate()
    qexecute()
    6.tTransaction     
    Connection con=DriverManager.getConnectio("jdbc:odbc:jia","sa","123");
    con.setAutoCommit(false);//關閉自動提交模式
    Statement stmt = con.createStatement();   
    stmt.qexecute(sql);   
    stmt.qexecute(sql);   
    stmt.qexecute(sql);     
    con.commit();           //提交 
    con.setAutoCommit(true);//開啟自動提交模式
    con.rollback();         //回滾
    7.關閉連接對象
    con.close();
    con.isClosed();

    JDBC連接數據庫

    方法:
    1.Oracle8/8i/9i數據庫(thin模式)
    Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
    String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl為數據庫SID
    String user="test";
    String password="test";
    Connection conn= DriverManager.getConnection(url,user,password); 
    2.DB2數據庫
    Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
    String url="jdbc:db2://localhost:5000/sample"; //sample為你的數據庫名
    String user="admin";
    String password="";
    Connection conn= DriverManager.getConnection(url,user,password); 
    3.Sql Server7.0/2000數據庫
    Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
    String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //mydb為數據庫
    String user="sa";
    String password="";
    Connection conn= DriverManager.getConnection(url,user,password); 
    4.Sybase數據庫
    Class.forName("com.sybase.jdbc.SybDriver").newInstance();
    String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB為你的數據庫名
    Properties sysProps = System.getProperties();
    SysProps.put("user","userid");
    SysProps.put("password","user_password");
    Connection conn= DriverManager.getConnection(url, SysProps); 
    5.Informix數據庫
    Class.forName("com.informix.jdbc.IfxDriver").newInstance();
    String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver;
    user=testuser;password=testpassword"; //myDB為數據庫名
    Connection conn= DriverManager.getConnection(url); 
    6.MySQL數據庫
    Class.forName("org.gjt.mm.mysql.Driver").newInstance();
    String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB為數據庫名
    Connection conn= DriverManager.getConnection(url); 
    7.PostgreSQL數據庫
    Class.forName("org.postgresql.Driver").newInstance();
    String url ="jdbc:postgresql://localhost/myDB" //myDB為數據庫名
    String user="myuser";
    String password="mypassword";
    Connection conn= DriverManager.getConnection(url,user,password); 
    8.access數據庫直連用ODBC的
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
    String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb");
    Connection conn = DriverManager.getConnection(url,"","");
    Statement stmtNew=conn.createStatement() ;

    posted @ 2010-02-23 10:33 junly 閱讀(326) | 評論 (0)編輯 收藏

    J2EE平臺由一整套服務(Services)、應用程序接口(APIs)和協議構成,它對開發基于Web的多層應用提供了功能支持。在本文中將解釋支撐J2EE的13種核心技術:

    JDBC,JNDI,EJBs,RMI,JSP,Javaservlets,XML,JMS,JavaIDL,JTS, JTA,JavaMail和JAF,同時還將描述在何時、何處需要使用這些技術。當然,我還要介紹這些不同的技術之間是如何交互的。此外,為了讓您更好地 感受J2EE的真實應用,將在WebLogic應用服務器,來自BEA Systems公司的一種廣為應用的產品環境下來介紹這些技術。不論對于Web Logic應用服務器和J2EE的新手,還是那些想了解J2EE能帶來什么好處的項目管理者和系統分析員,相信本文一定很有參考價值。

    一、宏觀印象:分布式結構和J2EE

    過去,二層化應用--通常被稱為client/server應用--是大家談論的最多的。在很多情況下,服務器提供的惟一服務就是數據庫服務。在這 種解決方案中,客戶端程序負責數據訪問、實現業務邏輯、用合適的樣式顯示結果、彈出預設的用戶界面、接受用戶輸入等。client/server結構通常 在第一次部署的時候比較容易,但難于升級或改進,而且經常基于某種專有的協議,通常是某種數據庫協議。它使得重用業務邏輯和界面邏輯非常困難。更重要的 是,在Web時代,二層化應用通常不能體現出很好的伸縮性,因而很難適應Internet的要求。

    Sun設計J2EE的部分起因就是想解決二層化結構的缺陷。于是,J2EE定義了一套標準來簡化N層企業級應用的開發。它定義了一套標準化的組件,并為這些組件提供了完整的服務。J2EE還自動為應用程序處理了很多實現細節,如安全、多線程等。

    用J2EE開發N層應用包括將二層化結構中的不同層面切分成許多層。一個N層化應用A能夠為以下的每種服務提供一個分開的層:

    顯示:在一個典型的Web應用中,客戶端機器上運行的瀏覽器負責實現用戶界面。 字串1

    動態生成顯示:盡管瀏覽器可以完成某些動態內容顯示,但為了兼容不同的瀏覽器,這些動態生成工作應該放在Web服務器端進行,使用JSP、Servlets,或者XML(可擴展標記語言)和(可擴展樣式表語言)。 字串6

    業務邏輯:業務邏輯適合用SessionEJBs(后面將介紹)來實現。

    數據訪問:數據訪問適合用EntityEJBs(后面將介紹)和JDBC來實現。

    后臺系統集成:同后臺系統的集成可能需要用到許多不同的技術,至于何種最佳需要根據后臺系統的特征而定。

    您可能開始詫異:為什么有這么多的層?事實上,多層方式可以使企業級應用具有很強的伸縮性,它允許每層專注于特定的角色。例如,讓Web服務器負責提供頁面,應用服務器處理應用邏輯,而數據庫服務器提供數據庫服務。

    由于J2EE建立在Java2平臺標準版(J2SE)的基礎上,所以具備了J2SE的所有優點和功能。包括“編寫一次,到處可用”的可移植性、通過 JDBC訪問數據庫、同原有企業資源進行交互的CORBA技術,以及一個經過驗證的安全模型。在這些基礎上,J2EE又增加了對EJB(企業級Java組 件)、Javaservlets、Java服務器頁面(JSPs)和XML技術的支持。

    二、分布式結構與WebLogic應用服務器

    J2EE提供了一個框架--一套標準API--用于開發分布式結構的應用,這個框架的實際實現留給了第三方廠商。部分廠商只是專注于整個J2EE架 構中的的特定組件,例如Apache的Tomcat提供了對JSP和servlets的支持,BEA系統公司則通過其WebLogic應用服務器產品為整 個J2EE規范提供了一個較為完整的實現。

    WebLogic服務器已使建立和部署伸縮性較好的分布式應用的過程大為簡化。WebLogic和J2EE代你處理了大量常規的編程任務,包括提供事務服務、安全領域、可靠的消息、名字和目錄服務、數據庫訪問和連接池、線程池、負載平衡和容錯處理等。

    通過以一種標準、易用的方式提供這些公共服務,象WebLogic服務器這樣的產品造就了具有更好伸縮性和可維護性的應用系統,使其為大量的用戶提供了增長的可用性。

    J2EE技術

    在接下來的部分里,我們將描述構成J2EE的各種技術,并且了解WebLogic服務器是如何在一個分布式應用中對它們進行支持的。最常用的J2EE技術應該是JDBC、JNDI、EJB、JSP和servlets,對這些我們將作更仔細的考察。

    三、Java Database Connectivity(JDBC)

    JDBCAPI以一種統一的方式來對各種各樣的數據庫進行存取。和ODBC一樣,JDBC為開發人員隱藏了不同數據庫的不同特性。另外,由于JDBC建立在Java的基礎上,因此還提供了數據庫存取的平臺獨立性。 字串5

    JDBC定義了4種不同的驅動程序,現分述如下:

    類型1:JDBC-ODBCBridge

    在JDBC出現的初期,JDBC-ODBC橋顯然是非常有實用意義的,通過JDBC-ODBC橋,開發人員可以使用JDBC來存取ODBC數據源。 不足的是,他需要在客戶端安裝ODBC驅動程序,換句話說,必須安裝MicrosoftWindows的某個版本。使用這一類型你需要犧牲JDBC的平臺 獨立性。另外,ODBC驅動程序還需要具有客戶端的控制權限。

    類型2:JDBC-nativedriverbridge

    JDBC本地驅動程序橋提供了一種JDBC接口,它建立在本地數據庫驅動程序的頂層,而不需要使用ODBC。JDBC驅動程序將對數據庫的API從標準的JDBC調用轉換為本地調用。使用此類型需要犧牲JDBC的平臺獨立性,還要求在客戶端安裝一些本地代碼。 字串3

    類型3:JDBC-networkbridge

    JDBC網絡橋驅動程序不再需要客戶端數據庫驅動程序。它使用網絡上的中間服務器來存取數據庫。這種應用使得以下技術的實現有了可能,這些技術包括 負載均衡、連接緩沖池和數據緩存等。由于第3種類型往往只需要相對更少的下載時間,具有平臺獨立性,而且不需要在客戶端安裝并取得控制權,所以很適合于 Internet上的應用。

    類型4:PureJavadriver

    第4種類型通過使用一個純Java數據庫驅動程序來執行數據庫的直接訪問。此類型實際上在客戶端實現了2層結構。要在N-層結構中應用,一個更好的做法是編寫一個EJB,讓它包含存取代碼并提供一個對客戶端具有數據庫獨立性的服務。

    WebLogic服務器為一些通常的數據庫提供了JDBC驅動程序,包括Oracle,Sybase,MicrosoftSQLServer以及 Informix。它也帶有一種JDBC驅動程序用于Cloudscape,這是一種純Java的DBMS,WebLogic服務器中帶有該數據庫的評估 版本。

    以下讓我們看一個JDBC實例:在這個例子中我們假定你已經在Cloudscape中建立了一個PhoneBook數據庫,并且包含一個表,名為 CONTACT_TABLE,它帶有2個字段:NAME和PHONE。開始的時候先裝載CloudscapeJDBCdriver,并請求 drivermanager得到一個對PhoneBookCloudscape數據庫的連接。通過這一連接,我們可以構造一個Statement對象并用 它來執行一個簡單的SQL查詢。最后,用循環來遍歷結果集的所有數據,并用標準輸出將NAME和PHONE字段的內容進行輸出。

    import java.sql.*; 字串5 public class JDBCExample{public static void main( String args[] ){try{Class.forName("COM.cloudscape.core.JDBCDriver");Connection conn = DriverManager.getConnection("jdbc:cloudscape:PhoneBook");Statement stmt = conn.createStatement();String sql = "SELECT name, phone FROM CONTACT_TABLE ORDER BYname";ResultSet resultSet = stmt.executeQuery( sql ); 字串8 String name;String phone;while ( resultSet.next() ){name = resultSet.getString(1).trim();phone = resultSet.getString(2).trim();System.out.println( name + ", " + phone ); }catch ( Exception e ){// Handle exception heree.printStackTrace();}}}

    OK。接著來看一看JDBC是如何在企業應用中的進行使用。

    JDBC在企業級應用中的應用。以上實例其實是很基本的,可能有些微不足道。它假定了一個2層結構。在一個多層的企業級應用中,更大的可能是在客戶 端和一個EJB進行通信,該EJB將建立數據庫連接。為了實現和改進可伸縮性和系統性能, WebLogic服務器提供了對連接緩沖池connection pool的支持。

    Connection pool減少了建立和釋放數據庫連接的消耗。在系統啟動以后即可建立這樣的緩沖池,此后如故再有對數據庫的請求,WebLogic服務器可以很簡單地從緩 沖池中取出數據。數據緩沖池可以在WebLogic服務器的 weblogic.properties 文件中進行定義。

    在企業級應用的另一個常見的數據庫特性是事務處理。事務是一組申明statement,它們必須做為同一個statement來處理以保證數據完整 性。缺省情況下JDBC使用 auto-commit 事務模式。這可以通過使用Connection類的setAutoCommit() 方法來實現。現在已經對JDBC有了一些認識,下面該轉向JNDI了。

    四、Java Naming and Directory Interface (JNDI) 字串3

    JNDI API被用于執行名字和目錄服務。它提供了一致的模型來存取和操作企業級的資源如DNS和LDAP,本地文件系統,后者在應用服務器中的對象。在JNDI 中,在目錄結構中的每一個結點稱為context。每一個JNDI名字都是相對于context的。這里沒有絕對名字的概念存在。對一個應用來說,它可以 通過使用 InitialContext 類來得到其第一個context: 字串6

    Context ctx = new InitialContext();

    應用可以通過這個初始化的context經有這個目錄樹 來定位它所需要的資源或對象。例如,假設你在Weblogic服務器中展開了一個EJB并將home接口綁定到名字 myApp.myEJB ,那么該EJB的某個客戶在取得一個初始化context以后,可以通過以下語句定位home接口:

    MyEJBHome home = ctx.lookup( "myApp.myEJB" );

    在這個例子中,一旦你有了對被請求對象的參考,EJB的home接口就可以在它上面調用方法。我們將在下面的"Enterprise Java Beans"章節中做更多的介紹。

    以上關于JNDI的討論只是冰山之一角而已。如果要更進一步地在context中查找對象,JNDI也提供了一些方法來進行以下操作:將一個對象插 入或綁定到context。這在你展開一個EJB的時候是很有效的。從context中移去對象。列出context中的所有對象。創建或刪除子一級的 context。接下來,要開始關注EJB了。
    五、Enterprise Java Beans (EJB)

    J2EE技術之所以贏得某體廣泛重視的原因之一就是EJB。它們提供了一個框架來開發和實施分布式商務邏輯,由此很顯著地簡化了具有可伸縮性和高度 復雜的企業級應用的開發。EJB規范定義了EJB組件在何時如何與它們的容器進行交互作用。容器負責提供公用的服務,例如目錄服務、事務管理、安全性、資 源緩沖池以及容錯性。 字串8

    EJB規范定義了三種基本的bean類型:

    Stateless session beans: 提供某種單一的服務,不維持任何狀態,在服務器故障發生時無法繼續存在,生命期相對較短。例如,一個stateless sessionbean可能被用于執行溫度轉換計算。

    Stateful session bean: T提供了與客戶端的會話交互,可以存儲狀態從而代表一個客戶。典型例子是購物車。Stateful session bean在服務器故障時無法繼續生存,生命氣相對較短。每一個實例只用于一個單個的線程。

    Entity beans: 提供了一致性數據的表示-- 通常存放在數據庫中 -- 在服務器故障發生后能繼續存在。多用戶情況下可以使用EJB來表示相同的數據。entity EJB的一個典型例子是客戶的帳號信息。 字串2

    盡管有以上的區別,所有的EJB還是有許多的共同之處。它們都處理homeinterface。它定義了一個客戶端是如何創建與消亡EJB的。可以 在bean中對定義了客戶端方法的遠程接口進行調用;bean類則執行了主要的商務邏輯。描述EJB的開發已經超出了本文的范圍。但是,如果一個EJB已 經被開發了或者從第三方進行了購買,它就必須在應用服務器中進行發布。WebLogic Server 5.1帶有一個EJB Deployer Tool來協助處理EJB的發布。當你使用EJB Deployer Tool的時候,你要定義客戶端所用的JNDI名字來定位EJB。Deployer Tool將生成wrapper類來處理和容器的通信以及在一個jar文件中把被請求的Java類綁定在一起。

    一旦EJB被發布,客戶端就可以使用它的JNDI名字來定位EJB。首先,它必須得到一個到home接口的reference。然后,客戶端可以使 用該接口,調用一個create() 方法來得到服務器上運行的某個bean實例的句柄;最后,客戶端可以使用該句柄在bean中調用方法。了解 EJB后,讓我們再來看JSP。 字串4

    六、JavaServer Pages (JSPs) 字串4

    可能已經有許多人已經熟悉Microsoft的Active Server Pages(ASP)技術了。JSP和ASP相對應的,但更具有平臺對立性。他們被設計用以幫助Web內容開發人員創建動態網頁,并且只需要相對較少的代 碼。 即使Web設計師不懂得如何編程也可以使用JSP,因為JSP應用是很方便的。 JSP頁面由HTML代碼和嵌入其中的Java代碼所組成。服務器在頁面被客戶端所請求以后對這些Java代碼進行處理,然后將生成的HTML頁面返回給 客戶端的瀏覽器。 字串5

    下面來看一個JSP的簡單實例。它只顯示了服務器的當前日期和時間。雖然,對語法的具體解釋已經超出了本文的范圍,但我們還是可以很直觀地看到,Java代碼被放在 符號的中間,而Java的表達式則放在符號之間。

    <H1>Date JSP sample</H1><H2><% response.setHeader("Refresh", 5); %>The current date is <%= new Date() %>.</H2> 字串1

    下面是: Java servlets

    七、Java Servlets

    Servlet 提供的功能大多與JSP類似,不過實現的方式不同。JSP通常是大多數HTML代碼中嵌入少量的Java代碼,而servlets全部由Java寫成并且 生成HTML。Servlet是一種小型的Java程序,它擴展了Web服務器的功能。作為一種服務器端的應用,當被請求時開始執行,這和CGI Perl腳本很相似。Servlets和CGI腳本的一個很大的區別是:每一個CGI在開始的時候都要求開始一個新的進程 -- 而servlets是在servlet引擎中以分離的線程來運行的。因此servlets在可伸縮性上提供了很好的改進。

    在開發servlets的時候,您常常需要擴展javax.servlet.http.HttpServlet類,并且override一些它的方法,其中包括:

    service(): 作為dispatcher來實現命令-定義方法

    doGet(): 處理客戶端的HTTP GET請求。

    doPost(): 進行HTTP POST操作 字串7

    其它的方法還包括處理不同類型的HTTP請求 -- 可以參考HttpServlet API文檔。以上描述的是標準J2EE Servlet API的各種方法。WebLogic服務器提供了一個該API完整的實現途徑。一旦你開發了一個servlet,你就可以在 weblogic.properties 中加以注冊并由此可以在WebLogic服務器中對它進行配置。 字串8

    通過Java servlets,我們已經到達了J2EE主要技術的末尾了。但J2EE所提供的并不止于這些。下面的段落中我們將簡要地看一下現存的一些技術,包括RMI,Java IDL和CORBA, JTA, 以及XML,等等。 字串1

    八、Remote Method Invocation (RMI)

    正如其名字所表示的那樣,RMI協議是在遠程對象上調用一些方法。它使用了連續序列方式在客戶端和服務器端傳遞數據。RMI是一種被EJB使用的更下層的協議。 字串5

    九、Java IDL/CORBA 字串5

    在Java IDL的支持下,開發人員可以將Java和CORBA集成在一起。 他們可以創建Java對象并使之可在CORBA ORB中展開, 或者他們還可以創建Java類并作為和其它ORB一起展開的CORBA對象的客戶。后一種方法提供了另外一種途徑,通過它Java可以被用于將你的新的應 用和legacy系統相集成。 字串4

    十、Java Transaction Architecture (JTA)/Java Transaction Service (JTS)

    JTA定義了一種標準的API,應用系統由此可以存取各種事務監控。JTS是CORBA OTS事務監控的基本的實現。JTS規定了事務管理器的實現方式。該事務管理器是在高層支持Java Transaction API (JTA)規范,并且在較底層實現OMG OTS specification的Java映像。JTS事務管理器為應用服務器、資源管理器、獨立的應用以及通信資源管理器提供了事務服務。

    十一、JavaMail and JavaBeans Activation Framework

    JavaMail是用于存取郵件服務器的API,它提供了一套郵件服務器的抽象類。僅支持SMTP服務器,也支持IMAP服務器。JavaMail 利用JavaBeans Activation Framework (JAF)來處理MIME-編碼的郵件附件。MIME的字節流可以被轉換成Java對象,或者轉換自Java對象。由此大多數應用都可以不需要直接使用 JAF。

    十二、Java Messaging Service (JMS)

    JMS是用于和面向消息的中間件相互通信的應用程序接口(API)。它既支持點對點的域,有支持發布/訂閱(publish/subscribe) 類型的域,并且提供對下列類型的支持:經認可的消息傳遞,事務型消息的傳遞,一致性消息和具有持久性的訂閱者支持。JMS還提供了另一種方式來對您的應用 與legacy backend系統相集成。

    十三、Extensible Markup Language (XML) 字串7

    XML是一種可以用來定義其它標記語言的語言。它被用來在不同的商務過程中共享數據。XML的發展和Java是相互獨立的,但是,它和Java具有 的相同目標正是平臺獨立性。通過將Java和XML的組合,您可以得到一個完美的具有平臺獨立性的解決方案。目前正有許多不同的公司在為Java和XML 的組合而努力。如果要了解更多的這方面的信息,可以訪問Sun的Java-XML頁面,或者IBM developerWorks的XML Zone。

     

    posted @ 2010-02-21 16:28 junly 閱讀(339) | 評論 (0)編輯 收藏
    僅列出標題
    共18頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    主站蜘蛛池模板: 野花香在线视频免费观看大全| 麻豆高清免费国产一区| 国产亚洲欧洲Aⅴ综合一区| 水蜜桃视频在线观看免费播放高清| 图图资源网亚洲综合网站| 免费国产黄线在线观看 | 一级看片免费视频| 亚洲国产成人精品不卡青青草原| 成人A级毛片免费观看AV网站| 丰满少妇作爱视频免费观看| 亚洲国产成人久久| 亚洲成a人在线看天堂无码| 久久w5ww成w人免费| 美女露隐私全部免费直播| 亚洲午夜在线电影| 亚洲AV无码一区二三区| 91成人免费观看| 男女猛烈激情xx00免费视频| 亚洲人成日本在线观看| 亚洲午夜福利在线观看| 国产日产成人免费视频在线观看| 免费无码成人AV在线播放不卡| 国产成人综合亚洲一区| 亚洲中文字幕人成乱码| 亚洲午夜久久久久久噜噜噜| 国产小视频免费观看| 91香蕉成人免费网站| 在线观看片免费人成视频播放| 亚洲AV无码一区二区三区电影 | 波多野结衣中文一区二区免费 | 亚洲熟女少妇一区二区| 日本不卡视频免费| 四虎1515hh永久久免费| 精品在线免费观看| 丰满妇女做a级毛片免费观看| 亚洲经典千人经典日产| 在线观看日本亚洲一区| 亚洲视频在线观看网址| 亚洲成人精品久久| 亚洲国产精品特色大片观看完整版| 免费人成在线观看网站视频|