簡體   English   中英

如何防止配置文件重復加載? 靜態持有它不起作用

[英]How to prevent configuration file from repeatedly reloading? Holding it statically is not working

我正在寫一個基於標記的庫 ,當找到第一個標記時,該會加載一些配置(從填充屬性的文本文件開始)。

配置對象直接靜態地保存在每個Taglet對象中,但是似乎它們被垃圾回收了,然后由javadoc.exe在隨后的taglet中重新生成,從而導致一遍又一遍地重新加載配置。

我是否正確理解了這一點,並且有解決辦法? 我如何才能使配置僅加載一次?

謝謝。


更新

如評論中所述,不,這不會影響性能或正確性。 由於javadoc.exe由一人在單台計算機上使用,因此性能並不是什么大問題。

但是,每次加載配置時(每次運行javadoc.exe至少五次),它都會使日志javadoc.exe ,並且會做一些中等程度的工作,包括從多個網站加載package-list ,加載和解析模板文件,以及一堆其他文件處理。 如果有任何方法可以防止在一次JavaDoc運行中多次發生這種情況,我想這樣做。

我沒有使用多線程的經驗,所以我可能完全錯了……但是,設置一個除了加載配置之外什么也不做的靜態守護線程,該怎么辦? 這個答案表明基於I / O的守護線程是一個壞主意,但我認為這意味着那些正在進行的I / O。

(我不確定這是否應該手動啟動和停止,或者進程本身是否有可能啟動守護程序線程……我將閱讀Bloch的Effective Java中的並發性章節。 )

如果由不帶父子關系的不同ClassLoader的兩個類必須共享數據,則常規的Java語言構造將不起作用。 如果可以使用Class對象或實例,則即使它是由不同的加載程序加載的同一類,也必須通過Reflection訪問它們。

此外,通過堆變量傳遞數據將無效,因為兩個ClassLoader建立了自己的“命名空間”,因此由兩個不同的加載器加載的創建兩個不同的Class對象的Class也將具有其static變量的不同副本。 您需要一個獨立於自己的類的存儲。

幸運的是,該存儲存在於Taglets的上下文中。 register方法接收Map包含所有先前登記的Taglets。 但是,除了必須使用Reflection而不是instanceofClass比較來查找“朋友” Taglets之外,還有另一個障礙:JavaDoc實現會將Taglets包裝在另一個對象中。

放在一起,您可以將查找和共享邏輯實現到Taglets的基類中,並讓Taglets的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;
    }
  }
}

然后,將以如下方式實現Taglet:

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…

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM