Global code initialization in Java
Since the JVM loads classes and code on-demand, there is no way to have initialization code in some random class (apart from the class containing the main() function) and have it run as the JVM starts. I'm aware that the very thought of this goes contrary to the JVM design. However, sometimes you want to do stuff like this, and I'm curious if there's some "standard" way of doing it, apart from having a function with a long, centralized list of initialization functions to call somewhere, and call them from the main() function.
The specific reason I'm wondering is because I have a program with a GUI system. This program connects to a server and acts kind of like a graphical terminal, allowing the server to create widgets to interact with the user. In order to do this, the widgets need to have some kind of ID that the server can use to reference them over the protocol, and there needs to be some kind of registry of such IDs. Right now, I'm using a global map of such IDs, mapping to instances of a WidgetFactory class, and I'm initializing those IDs in a static {} block in the base Widget class, kind of like this:
public class Widget {
private final static Map<String, WidgetFactory> widgets = new HashMap<String, WidgetFactory();
static {
widgets.put("wnd", Window.factory);
widgets.put("lbl", Label.factory);
widgets.put("text", TextEntry.factory);
widgets.put("btn", Button.factory);
}
}
However, as you can probably tell, this list grows large and unwieldy with growing numbers of widget types, and I also find it horribly ugly to centralize the widget logic in this way, when each widget type could instead be entirely self-contained in its own file. I would much prefer if I could do something like this in every file defining a widget class:
public class Label extends Widget {
static {
Widget.register("lbl", new WidgetFactory() {...});
}
}
But, for the aforementioned reasons, this particular method of doing it is obviously not possible.
It's not that I can't think of any ways to do this, but they all seem to possess varying degrees of ugliness, and I also think I can't really be the first one to grapple with this problem, so I guess what I want to ask is if there is, at least, some more-or-less "standard" way of doing these kinds of things. I would prefer not having to reinvent this partic开发者_如何学编程ular wheel if I can avoid to.
i think you could save id's and theclass name of widget you need in a temporally file, then use reflection to instance them, and also you can use a xml file.
On startup, iterate through all .class
files in your widget package folder and load them using a class loader. The widget's ID can be e.g. based on the class name or stored in an annotation. If you want, you can support loading from several widget directories, from inside JAR files etc.
I'm sure there are libraries to help with this and hope someone will edit this answer to point to one.
For the record, I've finally come to terms with the weirdness that no standard solution for this problem appears to exist, so I wrote one, which works by providing an annotation processor which collects classes annotated with Discoverable
annotations into generated text files.
This is still a centralized list, of course, but since it's autogenerated from decentralized annotations (which is not necessarily more strange that autogenerated ELF sections of initialization code, which is what GCC produces for C programs), I'm OK with that.
精彩评论