0

最初のタグレットが見つかったときに、いくつかの構成をロードします (プロパティで満たされたテキストファイルから始まります)。

構成オブジェクトは各Tagletオブジェクトに直接静的に保持されていますが、ガベージ コレクションが行わjavadoc.exeれ、後続のタグレットで再生成され、構成が何度も再ロードされているようです。

私はこれを正しく理解していますか?それを回避する方法はありますか? 構成が一度だけロードされるようにするにはどうすればよいですか?

ありがとう。


アップデート

コメントで述べたように、いいえ、これはパフォーマンスや正確性には影響しません。1 台のマシンで 1 人が使用するためjavadoc.exe、パフォーマンスはあまり問題になりません。

ただし、構成が読み込まれるたびにログが乱雑になり (実行ごとに少なくとも 5 回)、複数の Web サイトからの の読み込み、テンプレート ファイルの読み込みと解析、およびその他のファイル処理の束など、javadoc.exeやや重い処理が行われます。 package-list. 1 回の JavaDoc の実行でこれが何度も発生するのを防ぐ方法があれば、そうしたいと思います。

私はマルチスレッドの経験がないので、これは完全に間違っているかもしれません...しかし、構成をロードしてからすべてを静的に保持するだけのデーモンスレッドをセットアップするのはどうですか? この回答は、I/O ベースのデーモン スレッドが悪い考えであることを示唆していますが、それは進行中の I/O を実行するものを意味すると思います。

(これが手動で開始および停止する必要があるものなのか、それともプロセス自体がデーモンスレッドを開始できるのかはわかりません... BlochのEffective Javaの並行性の章を読むつもりです.. .)

4

1 に答える 1

0

ClassLoader親子関係のない異なる によってロードされた 2 つのクラスがデータを共有する必要がある場合、通常の Java 言語構造は機能しません。Classオブジェクトまたはインスタンスを手に入れることができれば、異なるローダーによってロードされたばかりの同じクラスであっても、リフレクションを介してそれらにアクセスする必要があります。

さらに、ヒープ変数を介してデータを渡すと、両方ClassLoaderが独自の「名前空間」を確立するため機能しません。したがって、2 つの異なるオブジェクトを作成する 2 つの異なるローダーによってロードされたクラスには、変数Classの異なるコピーも含まれます。static独自のクラスから独立したストレージが必要です。

ありがたいことに、そのストレージはタグレットのコンテキストに存在します。このregisterメソッドは、Map以前に登録されたすべてのタグレットを含む を受け取ります。instanceofしかし、「友達」のタグレットを見つけるために、または比較ではなくリフレクションを使用する必要があるという事実に加えて、Class別の障害があります。JavaDoc の実装では、タグレットを別のオブジェクト内にラップすることです。

すべてをまとめると、タグレットの基本クラスに検索と共有のロジックを実装し、タグレットのregisterメソッドにそれを呼び出させることができます。

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;

public abstract class Base
{
  static Properties CONFIG=new Properties();

  static void initProperties(Map<?, ?> fromTagManager) {
    String className=Base.class.getName();
    for(Object o: fromTagManager.values()) {
      o=extractTagLet(o);
      if(o==null) continue;
      for(Class<?> cl=o.getClass(); cl!=null; cl=cl.getSuperclass())
        if(cl.getName().equals(className) && initFromPrevious(cl)) return;
    }
    // not found, first initialization
    try {
      CONFIG.load(Base.class.getResourceAsStream("config.properties"));
    } catch(IOException ex) {
      throw new ExceptionInInitializerError(ex);
    }
  }

  private static Object extractTagLet(Object o) {
    if(!o.getClass().getSimpleName().equals("LegacyTaglet"))
      return o;
    try {
      Field f=o.getClass().getDeclaredField("legacyTaglet");
      f.setAccessible(true);
      return f.get(o);
    } catch(NoSuchFieldException | IllegalAccessException ex) {
      ex.printStackTrace();
    }
    return null;
  }

  private static boolean initFromPrevious(Class<?> cl) {
    // this is the same class but loaded via a different ClassLoader
    try {
      Field f=cl.getDeclaredField("CONFIG");
      f.setAccessible(true);
      CONFIG=(Properties)f.get(null);
      return true;
    } catch(NoSuchFieldException | IllegalAccessException ex) {
      return false;
    }
  }
}

次に、タグレットは次のように実装されます。

import java.util.Map;
import com.sun.javadoc.Tag;
import com.sun.tools.doclets.Taglet;

public class ExampleTaglet extends Base implements Taglet {
  @SuppressWarnings("unchecked")
  public static void register(@SuppressWarnings("rawtypes") Map map) {
    initProperties(map);
    final ExampleTaglet taglet = new ExampleTaglet();
    final String name = taglet.getName();
    map.remove(name);// must ensure new Taglet is the last one (LinkedHashMap)
    map.put(name, taglet);
  }

  // implement the Taglet interface below…
于 2014-06-02T13:18:42.660 に答える