我正在开发一个简单的插件系统,其中第三方插件实现了Plugin
接口。扫描JAR目录,并使用Constructor#newInstance
实例化实现类。
问题是,这些插件回调到插件主机的register*
方法。这些注册使用Plugin
实例作为句柄。我的问题是如果构造函数决定失败并抛出一半,如何清理这些注册。
InvocationTargetException
似乎没有任何内容可以获取实例。 有没有办法获得抛出构造函数的异常实例?
P.S。:通常强烈建议用户构造函数不做任何事情,但实际上人们都是这样做的。
答案 0 :(得分:1)
是否可以通过holder对象进行注册,然后在成功构建插件类之后将其用于实际的插件注册?我在考虑这样的事情:
public class MyPlugin extends BasePlugin {
public MyPlugin(PluginRegistry registry) {
super(registry);
// here be things which may cause an exception
// to be thrown, among other things
}
}
public interface PluginRegistry {
// method(s) for registration
}
public class PluginRegistryHolder implements PluginRegistry {
// implementations of the required method(s) for registration
// also a method for getting temporary registration data from within the class
}
// Actual usage in your code
public void registerPlugin(final String className) {
PluginRegistryHolder h = new PluginRegistryHolder();
Constructor c = /* acquire correct constructor, omitted for clarity */
try {
Object o = c.newInstance(new Object[] {h});
this.actualRegistry.register(o, h.getRegistrationData());
} catch (Throwable t) { /* die */
}
}
所以基本上优雅地处理注册,永远不要让插件类直接注册,而是通过托管代理注册。
答案 1 :(得分:1)
您实际要问的是,当构造函数抛出异常时是否有办法获取(部分)实例。
答案是否定的。但不是因为实例“死了”。事实上,对于实例的引用仍然可以被应用程序的其他部分访问和使用...如果它在构造函数完成之前已经“发布”。
真正的原因是,创建或抛出异常都不会记录与执行创建/抛出的方法或构造函数关联的实例。
您需要以其他方式解决此问题。我的建议是你规定这些插件类只能将实例注册为构造函数的最后一个语句;即,当不再抛出与初始化相关的异常时。