繁体   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