简体   繁体   English

如何防止配置文件重复加载? 静态持有它不起作用

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

I'm writing a taglet-based library , which, when the first taglet is found, loads some configuration (starting with a text-file filled with properties). 我正在写一个基于标记的库 ,当找到第一个标记时,该会加载一些配置(从填充属性的文本文件开始)。

The configuration object is being held statically directly in each Taglet object, but it seems that they are being garbage collected and then respawned by javadoc.exe in a subsequent taglet, causing the configuration to be reloaded over and over again. 配置对象直接静态地保存在每个Taglet对象中,但是似乎它们被垃圾回收了,然后由javadoc.exe在随后的taglet中重新生成,从而导致一遍又一遍地重新加载配置。

Am I understanding this correctly, and is there a way around it? 我是否正确理解了这一点,并且有解决办法? How can I make it so that configuration loads only once? 我如何才能使配置仅加载一次?

Thanks. 谢谢。


UPDATE 更新

As mentioned in the comments, no, this does not impact performance or correctness. 如评论中所述,不,这不会影响性能或正确性。 Since javadoc.exe is used by a single person on a single machine, performance is not much of an issue. 由于javadoc.exe由一人在单台计算机上使用,因此性能并不是什么大问题。

However, it clutters up the log each time configuration is loaded (at least five times per javadoc.exe run), and it does some moderately-heavy stuff, including loading package-list s from multiple websites, loading and parsing template files, and a bunch of other file processing. 但是,每次加载配置时(每次运行javadoc.exe至少五次),它都会使日志javadoc.exe ,并且会做一些中等程度的工作,包括从多个网站加载package-list ,加载和解析模板文件,以及一堆其他文件处理。 If there is any way to prevent this from happening many times in a single JavaDoc run, I would like to. 如果有任何方法可以防止在一次JavaDoc运行中多次发生这种情况,我想这样做。

I have no experience with multithreading, so I may have this completely wrong...but what about setting up a daemon thread that does nothing but load configuration and then hold it all statically? 我没有使用多线程的经验,所以我可能完全错了……但是,设置一个除了加载配置之外什么也不做的静态守护线程,该怎么办? This answer suggests that an I/O-based daemon thread is a bad idea, but I think it means ones that do ongoing I/O. 这个答案表明基于I / O的守护线程是一个坏主意,但我认为这意味着那些正在进行的I / O。

(I'm not sure if this would be something that should be manually started and stopped, or if its possible for the process itself to start the daemon thread... I'm going to read the concurrency chapters in Bloch's Effective Java...) (我不确定这是否应该手动启动和停止,或者进程本身是否有可能启动守护程序线程……我将阅读Bloch的Effective Java中的并发性章节。 )

If two classes loaded by different ClassLoader s without parent-child relationship have to share data, the normal Java language constructs do not work. 如果由不带父子关系的不同ClassLoader的两个类必须共享数据,则常规的Java语言构造将不起作用。 If you can get hands on a Class object or an instance, you have to access them via Reflection, even if it is the same class just loaded by different loaders. 如果可以使用Class对象或实例,则即使它是由不同的加载程序加载的同一类,也必须通过Reflection访问它们。

Further, passing the data via heap variables won't work as both ClassLoader s establish their own “namespace” hence a class loaded by two different loader creating two distinct Class objects will have their distinct copies of static variables as well. 此外,通过堆变量传递数据将无效,因为两个ClassLoader建立了自己的“命名空间”,因此由两个不同的加载器加载的创建两个不同的Class对象的Class也将具有其static变量的不同副本。 You need a storage which is independent from your own classes. 您需要一个独立于自己的类的存储。

Thankfully, that storage exists in the context of Taglets. 幸运的是,该存储存在于Taglets的上下文中。 The register method receives a Map containing all previously registered Taglets. register方法接收Map包含所有先前登记的Taglets。 But besides the fact that you have to use Reflection rather than instanceof or Class comparison to find your “friend” Taglets, there is another obstacle: the JavaDoc implementation will wrap your Taglets within another object. 但是,除了必须使用Reflection而不是instanceofClass比较来查找“朋友” Taglets之外,还有另一个障碍:JavaDoc实现会将Taglets包装在另一个对象中。

Putting it all together, you could implement the find-and-share logic into a base class of your Taglets and let the register method of the Taglets call it: 放在一起,您可以将查找和共享逻辑实现到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;
    }
  }
}

Then a Taglet will be implemented like this: 然后,将以如下方式实现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.

相关问题 使用Commons配置自动重新加载属性文件不起作用 - Auto reloading properties file using commons configuration is not working 如何防止在while循环中字符串重复打印? - How to prevent string from printing repeatedly in while loop? 防止android活动重新加载 - Prevent android activities from reloading 防止用户在Eclipse中按住键 - Prevent User from holding key down in Eclipse 在Android中如何阻止用户按住主页按钮显示最近启动的应用程序? - In Android how do I prevent the user from holding the home button to display recently launched apps? 防止导入的库使用我的日志配置文件 - Prevent imported libraries from using my logging-configuration file 如何在不保持文件打开的情况下跟踪Java中的“Tail -f”之类的文件(防止重命名/删除) - How can I follow a file like “Tail -f” does in Java without holding the file open (Prevent rename/delete) 重新加载jsp页面后,如何防止重新加载嵌入式applet? - How can I prevent embedded applet from reloading after I reload jsp page? 访问其他活动后返回时如何防止活动重新加载? - How to prevent activity from reloading itself when coming back after visiting other activities? 从保存的文件重新加载JTree - Reloading a JTree from a saved file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM