开发者

Getting the instance when Constructor#newInstance throws?

I'm working on a simple plugin system, where third party plugins implement a Plugin interface. A directory of JARs is scanned, and the implementing classes are instantiated with Constructor#newInstance.

The thing is, these plugins call back into register* methods of the plugin host. These registrations use the Plugin instance as a handle. My problem is how to clean up these registrations if the constructor decides to fail and throw halfway through.

InvocationTargetException doesn't seem to have anything on it to get the instance. Is there a way to get at the instance of an exception throwing constructor?

P.S.: It's typically strongly advised开发者_Go百科 to users that the constructor not do anything, but in practice people are doing it any ways.


What you are in effect asking is whether there is a way to get hold of the (partial) instance when a constructor throws an exception.

The answer is No. But it is not because the instance is "dead". In fact the reference to the instance could still be reachable and usable by other parts of the application ... if it has been "published" before the constructor completed.

The real reason is that neither creating or throwing an exception records the instance associated with the method or constructor doing the creating / throwing.


You will need to solve this some other way. My suggestion is you make it a rule that these plugin classes must only register the instance as the last statement of the constructor; i.e. when no more initialization-related exceptions could be thrown.


Is it possible to do the registration through a holder object which is then used for actual plugin registration after the plugin class has been constructed successfully? I'm thinking of something like this:

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 */
    }
}

So basically handle the registration gracefully and never let the plugin class register directly but instead through a managed proxy.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜