アプレット開発のためのベストプラクティス

アプレット開発者ガイド > Java Plug-in とアプレットのアーキテクチャー > アプレット開発のためのベストプラクティス

目次


はじめに

アプレットには、複雑な実行時環境のほか、アプレットがさまざまなブラウザや Java Plug-in の各種のバージョンで予測どおりに実行されることを保証するために考慮する必要のあるいくつかの問題があります。このドキュメントでは、アプレットの開発および配備のためのベストプラクティスについて説明します。

静的な状態を避ける

クラスローダーキャッシュによって取得されたメモリーがほかの目的に必要ない場合は、アプレット内に格納されている値を呼び出しの間で持続させることもできます。ただし、その動作に依存することはできません。一般に、アプレットは状態を持たないようにしてください。持続的記憶領域が必要な場合は、ブラウザの cookie を使用します。

start メソッドからできるだけすばやく復帰する

start が終了しないと、stop を呼び出せません。これが重要なのは、destroy メソッドが終了したあと、ガベージコレクションが実行されるためです。アプレットが start メソッド内に長くとどまった場合、そのアプレットが正しくティアダウンされない可能性があります。(ティアダウンされて、ガベージコレクションは実行されるが、アプレットの初期化中に取得されたリソースが正しく解放されない可能性がある。)

Clock デモなどの計算量の多いアプリケーションの場合は、ソースコードから次の抜粋に示すように、Runnable インタフェースを実装し、必要な一連の作業を run メソッドで実行して、実際の作業を実行する別のスレッドを起動するのがこつです。

public class Clock extends Applet implements Runnable { 
  private volatile Thread timer;    // The thread that displays the clock
  ... 
  public void start() {
    timer = new Thread(this);       // Create the thread and start it
    timer.start();
  }
   
  public void stop() {
    timer = null;                   // Release the thread resource
  }

  public void run() {
    Thread me = Thread.currentThread();
    while (timer == me) {
      try {
        Thread.currentThread().sleep(100);
      } 
      catch (InterruptedException e) { 
      }
      repaint();
    }
  } 
  ...

ここでのアクションは、新しいスレッドで実行されている Clock インスタンスを一時停止することです (そのため、そのインスタンスへのポインタを格納する必要がある)。そのすべてを実行する必要のないアプレットは、その処理コードを単純に run メソッドに置くことができます。

スプレッドシートのデモなどの対話型アプリケーションの場合は、ソースコードから次の抜粋に示すように、ほとんどの時間がイベント処理スレッドに費やされるため、その目標が簡単に達成されます。

public class SpreadSheet extends Applet
  implements MouseListener, KeyListener  // Event processing
{
  public void init() {
    ...
    addMouseListener(this);
    addKeyListener(this);
  } 
  ...
  public void start() {
        isStopped = false;
  }

  public void stop() {
         isStopped = true;
  }

  public void keyTyped(KeyEvent e) {    // Invoked when an event occurs
    ...
  }
  public void mousePressed(MouseEvent e) {
    ...
  }
  
  ...
class CellUpdater extends Thread {
  ... 
  public void run() {
    ...
      if (!target.app.isStopped && !target.paused) {
                        target.app.repaint();
      }

この特定の実装では、各セルに独自の更新スレッドがあります。更新は、セルが選択されると一時停止され、アプレットが終了した場合にのみ完全に停止します。重要な点は、アプレットの start および stop メソッドがアプレットの状態だけを追跡することです。ほとんどの時間が、ユーザーのキーストロークまたはマウスクリックを待機している、基盤となるイベント処理スレッドに費やされます。アプレットの実際の作業は、これらのいずれかのイベントに応答して実行されます。

アプレットに ID を付与する

ID は名前空間を定義し、データ階層のすべてのレベルでの正しいネーミングを保証します。

<applet 
  id="myApplet" 
  name="myApplet"
  ...

クラスローダーキャッシュを無効にする

真にステートレスなアプレットは、static 変数内に以前に格納された値に依存しません。これらの値が保持されるのを前提にすることはできないため、ステートレスなアプレットを作成することは良い考えです。ただし、ユーザーは引き続き状態を格納できます。アプレットコード内にではなく、データを単に、所属先であるユーザーの場所に格納するだけです。

状態を持たないアプリケーションを実装するには、プログラムに格納された値を使用するのではなく、アプレットが初期設定を持続的記憶領域から取得できるように、ブラウザの cookie にアクセスするか、または JNLP を起動して Java Web Start のマフィンを使用します。

アプレットが間違いなく状態を持たないようにするには、classloader_cache 属性を使用してキャッシュを無効にします。たとえば、

<applet
  ... 
  classloader_cache="false" 

この設定によって、アプレットが状態を持たず、システムの残りの部分や、そのアプレットのほかのインスタンスから真に切り離されることが保証されます。また、誤って保持された状態に影響されることがなくなるため、アプレットが毎回正確に同じ方法で実行されることも保証されます。

注:
ユーザーが同じアプレットを繰り返し再実行することが予測されるまれなケースでは、パフォーマンスのために実稼働環境ではキャッシュを有効にしたままにすることを考慮する可能性もありますが、品質を保証するために開発中はキャッシュを無効にしてください。

JavaScript からアプレット GUI を操作するためのプロキシを設定する

スレッドの競合を回避するために、Swing または AWT GUI を JavaScript から直接更新しないでください。代わりに、要求を適切なディスパッチスレッドに転送するプロキシを設定します。

プロセス間呼び出しを短時間に保つ

Java から JavaScript への呼び出しや、JavaScript から Java への呼び出しにかかる時間を最小限に抑えます。このような呼び出しで、長時間実行される作業を行わないでください。そうしないと、デッドロックが発生する可能性があります。呼び出しを短時間に保つには、次のようにします。

  1. JavaScript から呼び出される Java メソッドでは、作業を実行するための別のスレッドを起動します。
  2. JavaScript 関数で多くの作業を実行する場合は、ブラウザの負荷を軽減するために、コードを Java プロセスに移動し、その作業を別のスレッドで実行します。

往復のプロセス間呼び出しを避ける

Java を呼び出しているときは、可能なかぎり、JavaScript へのコールバックを行わないでください。また、その逆も同様です。その元のプラグインでこれを行った場合、以前はブラウザがロックされました。その現象は発生しなくなりましたが、往復の呼び出しによって、処理時間の大幅な遅延が発生します。

JavaScript 関数に何かの作業を行うアプレットが必要な場合のベストプラクティスは、アプレットに作業を行うことを指示する値を返したあと、その結果を使用してコールバックするか、または invokeLater を使用してトラフィックの停止を最小限に抑えます。

Java のマルチスレッドを利用する

Java プラットフォームには、Thread、Swing invokeLater、AWT invokeLater などのクラスや、バックグラウンドのスレッドプールを保持する新しい ThreadPoolExecutor クラスで利用できる、強力なマルチスレッド機能があります。




Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.