Java 7 執行階段環境

警告:Java 7 執行階段已淘汰。Java 7 執行階段上的應用程式部署遭封鎖,而 Java SDK 1.9.72 版或以上則不允許構建 Java 7應用程式。

如果您的應用程式目前使用 Java 7 執行階段,則會自動遷移至 Java 8執行階段。Google 將繼續依照服務條款支援 Java 7 執行階段。請盡早遷移至 Java 8 執行階段

透過 App Engine,您可以建構使用 Google 可擴充基礎架構與服務的網路應用程式。

簡介

App Engine 會在「採用沙箱機制」的安全環境中使用 Java 8 JVM 執行 Java 網路應用程式。App Engine 會叫用應用程式的 Servlet 類別,在這個環境中處理要求並準備回應。

App Engine Java 7 執行階段以 OpenJDK 7 為基礎,在網路應用程式方面使用 Java Servlet 2.5 標準。您可在標準 WAR 目錄結構中提供應用程式的 Servlet 類別、JavaServer Pages (JSP)、靜態檔案與資料檔案,另外還有部署作業描述元 (web.xml 檔案) 與其他設定檔。App Engine 會根據部署作業描述元叫用 Servlet 來處理要求。

安全的「沙箱」環境會隔離您的應用程式,只用於提供服務及安全用途。這個環境會確認應用程式只能執行不干擾其他應用程式效能與擴充性的操作。例如,應用程式無法以某些方式產生執行緒、將資料寫入本機檔案系統,也無法任意建立網路連線,此外,應用程式也無法使用 JNI 或其他原生碼 (native code)。JVM 可以執行任何沙箱內允許的 Java 位元組碼。

App Engine 平台提供許多服務,您的程式碼可以呼叫這些服務。您的應用程式也可以設定會按指定間隔執行的排程工作

Java 留言板應用程式教學課程一文提供了使用 Java 技術與 App Engine 開發網路應用程式的介紹。

選取 Java 8 執行階段

Java 適用的 App Engine API 會以 appengine-api-*.jar 表示,並且包含做為 Cloud SDK 一部分的 App Engine SDK (其中 * 代表 API 和 App Engine SDK 的版本)。

您可以將這個 JAR 包含在應用程式的 WEB-INF/lib/ 目錄中,來選取應用程式使用的 API 版本,或者使用 Maven 來處理依附元件。如果 Java Runtime Environment 推出的新版本添加了與現有應用程式不相容的變更,則該環境將有新的版本號碼。 在您將 JAR 取代為新版本 (從較新的 App Engine SDK) 並重新上傳應用程式之前,應用程式將繼續使用舊版。

使用 Maven 來處理依附元件

您可以使用 Maven 管理所有依附元件。例如,這個 pom.xml 項目中包含 Maven Central 的最新 App Engine API (Rappengine-api-1.0-sdk):

<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-api-1.0-sdk</artifactId>
    <version><span class="notranslate exporttrans-dynamic">print setvar.appengine_java_version</span></version>
</dependency>

沙箱

為讓 App Engine 能跨多個網路伺服器發布應用程式要求,並且避免應用程式彼此干擾,應用程式會在受到限制的「沙箱」環境中執行。 在這個環境中,應用程式可以執行程式碼、儲存及查詢 Cloud Datastore 中的資料、使用 App Engine 郵件、網址擷取以及使用者服務,也可以檢查使用者的網路要求,以及準備回應。

App Engine 應用程式做不到的事情如下:

  • 寫入檔案系統。應用程式必須使用 Cloud Datastore 儲存永久資料。您可以從檔案系統讀取,而且可以使用所有以應用程式上傳的應用程式檔案。

  • 慢速回應。應用程式收到的網路要求必須在幾秒內處理完畢。處理序所需的回應時間如果太長,就會終止,以免導致網路伺服器負荷過重。

  • 進行其他種類的系統呼叫。

檔案系統

Java 應用程式無法使用任何類別寫入至檔案系統,例如 java.io.FileWriter。應用程式可以使用類別從檔案系統讀取自己的檔案,例如 java.io.FileReader。應用程式也可以將自己的檔案當成「資源」存取,例如使用 Class.getResource()ServletContext.getResource()

應用程式只能透過檔案系統存取當成「資源檔案」使用的檔案。根據預設,WAR 中的所有檔案都是「資源檔案」。您可以使用 appengine-web.xml 檔案將這些資源檔案排除在這組檔案之外。

java.lang.System

不適用於 App Engine 之 java.lang.System 類別的功能都會停用。

以下 System 方法不會在 App Engine 中執行任何動作:exit()gc()runFinalization()runFinalizersOnExit()

以下 System 方法會傳回 nullinheritedChannel()console()

應用程式無法提供或直接叫用任何原生的 JNI 程式碼。以下 System 方法會引發 java.lang.SecurityExceptionload()loadLibrary()setSecurityManager()

映射

應用程式可以完整、無限制地以映射方式存取本身的類別,

並查詢任何私人成員、呼叫 java.lang.reflect.AccessibleObject.setAccessible() 方法,及讀取/設定私人成員。

應用程式也可以映射在 JRE 與 API 類別,例如 java.lang.Stringjavax.servlet.http.HttpServletRequest,但是只能存取這些類別的公開成員,無法存取受保護或私人的成員。

應用程式無法映射於不屬於本身的任何其他類別,也無法使用 setAccessible() 方法規避這些限制。

自訂類別載入

App Engine 可以充分支援自訂類別載入。應用程式可以定義自身的 ClassLoader 子類別來實作應用程式專用類別邏輯。但請注意,App Engine 會覆寫所有 ClassLoaders,將相同權限指派給您的應用程式所載入的所有類別。如果您執行自訂類別載入,載入可疑的第三方程式碼時請多加留意。

類別載入器 JAR 排序

有時候可能需要重新定義掃描 JAR 檔案的類別順序,藉以解決類別名稱之間的衝突。在這些情況下,您可以在 <class-loader-config> 檔案中新增包含 <priority-specifier> 元素的 appengine-web.xml 元素,賦予特定 JAR 檔案優先載入順序。例如:

<class-loader-config>
  <priority-specifier filename="mailapi.jar"/>
</class-loader-config>

這樣會使「mailapi.jar」成為除了 war/WEB-INF/classes/ 目錄中的 JAR 檔案以外,第一個搜尋的 JAR 檔案類別。

如果將多個 JAR 檔案設定為優先,則會使用這些檔案的原始載入順序 (彼此的相對順序)。換句話說,<priority-specifier> 元素本身的順序無關緊要。

JRE 許可清單

是否能夠存取 Java 標準程式庫 (Java Runtime Environment,或稱 JRE) 中的類別,受限於 App Engine JRE 許可清單中的類別。

沒有簽署的 JAR 檔案

App Engine 的先行編譯與簽署的 JAR 檔案不相容。如果您的應用程式已先行編譯 (預設),就無法載入簽署的 JAR 檔案。 如果應用程式嘗試載入簽署的 JAR,App Engine 會在執行階段產生類似以下這樣的例外狀況:

java.lang.SecurityException: SHA1 digest error for com/example/SomeClass.class
    at com.google.appengine.runtime.Request.process-d36f818a24b8cf1d(Request.java)
    at sun.security.util.ManifestEntryVerifier.verify(ManifestEntryVerifier.java:210)
    at java.util.jar.JarVerifier.processEntry(JarVerifier.java:218)
    at java.util.jar.JarVerifier.update(JarVerifier.java:205)
    at java.util.jar.JarVerifier$VerifierStream.read(JarVerifier.java:428)
    at sun.misc.Resource.getBytes(Resource.java:124)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:273)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)

有兩種方法可以解決這個問題:

執行緒

Java 應用程式可以建立新執行緒,但做法有一些限制。這些執行緒的期限不能「超過」建立類別的要求本身的期限。

應用程式可以執行以下動作:

但是,您必須對 ThreadManager 使用其中一種方法來建立自己的執行緒,而不能自行叫用 new Thread() 或使用預設執行緒處理站

應用程式可對目前執行緒執行作業,例如 thread.interrupt()

每個要求都受限於 50 個並行要求執行緒之內。如果您嘗試在單次要求中建立超過 50 個執行緒,Java 執行階段將會擲回 java.lang.IllegalStateException

使用執行緒時,請使用高階並行物件,例如 ExecutorRunnable。這些物件會處理並行方面的許多細微但重要的細節,例如中斷排程和簿記

背景執行緒

手動或基本資源調度執行個體執行的程式碼可以啟動一個背景執行緒,這個執行緒的期限可以超過產生其本身之要求的期限。如此一來,執行個體便可執行任意定期或排程工作,將要求傳回使用者後,也可以繼續在背景執行。

Java 並行可能導致發生難以偵錯的問題。如要避免使用執行緒,請考慮使用工作佇列排程工作Pub/Sub

背景執行緒的記錄項目與產生執行緒的這些項目不同。如要進一步瞭解背景執行緒,請參閱 App Engine 的 ThreadManager 說明文件。

import com.google.appengine.api.ThreadManager;
import java.util.concurrent.atomic.AtomicLong;

AtomicLong counter = new AtomicLong();

Thread thread = ThreadManager.createBackgroundThread(new Runnable() {
  public void run() {
    try {
      while (true) {
        counter.incrementAndGet();
        Thread.sleep(10);
      }
    } catch (InterruptedException ex) {
      throw new RuntimeException("Interrupted in loop:", ex);
    }
  }
});
thread.start();

如果在自動調整資源配置服務中執行的程式碼嘗試啟動背景執行緒,則會引發例外狀況。

App Engine API 能夠建立的並行背景執行緒每執行個體不超過 10 個 (這項限制不適用於與 App Engine API 無關的一般 Java 執行緒。)

工具

支援的 IDE

Cloud Tools for Eclipse 將新的專案精靈與偵錯設定新增到您的 Eclipse IDE 供 App Engine 專案使用。您可即時從 Eclipse 內部將 App Engine 專案部署到實際工作環境。

Cloud Tools for IntelliJ 可讓您在 IntelliJ IDEA 中執行 App Engine 應用程式及偵錯。無須離開 IDE,就可以即時將 App Engine 專案部署至實際工作環境。

支援的建構工具

如要加快開發流程,您可以使用 Maven 或 Gradle 適用的 App Engine 快掛程式:

本機開發伺服器

開發伺服器會在本機電腦上執行您的應用程式,以進行開發與測試。伺服器會模擬 Cloud Datastore 服務。開發伺服器也會根據應用程式在測試期間執行的查詢,產生 Cloud Datastore 索引的設定。

AppCfg

AppCfg 包含在 Java 適用的 App Engine SDK 獨立版中。這個多用途工具會處理與在 App Engine 上執行之應用程式的指令行互動。AppCfg 可將您的應用程式上傳至 App Engine,或是只更新 Cloud Datastore 索引設定,以利在更新程式碼之前建構新的索引。此工具還可以下載應用程式的記錄資料,讓您能使用自己的工具分析應用程式的效能。

並行與延遲

應用程式的延遲對提供流量所需的執行個體數量影響最大。如果快速處理要求,一個執行個體就能處理許多要求。

單執行緒執行個體可以處理一個並行要求。因此,延遲與執行個體每秒能夠處理的要求數量之間具有直接關係。例如,延遲 10 毫秒相當於每個執行個體每秒處理 100 個要求。

多執行緒執行個體可以處理許多並行要求。因此,耗用的 CPU 和每秒要求數量之間具有直接關係。

Java 應用程式支援並行要求,因此,單一執行個體可以一邊處理新要求一邊等待其他要求完成。並行能大幅減少應用程式所需的執行個體數量,但您需要設計支援多工執行緒功能的應用程式。

例如,若一個 B4 執行個體 (約 2.4GHz) 處理一個要求需耗用 10 個 Mcycle,那麼您的每個執行個體每秒可以處理 240 個要求。若處理每個要求需耗用 100 個 Mcycle,則您的每個執行個體每秒可以處理 24 個要求。這些數字是理想情形,不過針對可在一個執行個體上完成的工作而言,算是相當實際。

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Java 8 適用的 App Engine 標準環境