[英]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而不是
instanceof
或Class
比较来查找“朋友” 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.