如果由不同的没有父子关系的 s 加载的两个类ClassLoader
必须共享数据,那么普通的 Java 语言结构不起作用。如果您可以获取Class
对象或实例,则必须通过反射访问它们,即使它是由不同加载器加载的同一个类。
此外,通过堆变量传递数据将不起作用,因为两者都ClassLoader
建立了自己的“命名空间”,因此由两个不同的加载器加载的类创建两个不同的对象也将具有它们不同的变量Class
副本。static
您需要一个独立于您自己的类的存储。
值得庆幸的是,该存储存在于 Taglets 的上下文中。该register
方法接收一个Map
包含所有先前注册的 Taglets。但是除了你必须使用反射而不是instanceof
比较Class
来找到你的“朋友” 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…