For registration and discovery of any kind of interface or class, in any module within the system, the NetBeans Platform supports two uniformly suitable solutions:
Factors that might determine which approach to take:
Lookup is available in versions for older JDKs and thus you can use it as a replacement of ServiceLoader when running on JDKs older than 1.6.
Lookup is ready to work inside of the NetBeans runtime container. It knows how to discover all the modules in the system, how to effectively read its defined services, etc.
Lookup supports listeners. Client code can attach a listener and observe changes in lookup content. This is a necessary improvement to adapt to the dynamic environment created by the NetBeans runtime container, where modules can be enabled or disabled at runtime, which in turn can affect the set of registered service providers.
Lookup is extensible and replaceable. While the ServiceLoader class in JDK 1.6 is a final class with hard-coded behavior, the NetBeans Lookup is an extensible class that allows various implementations. This can be useful while writing unit tests. Or you can write an enhanced version of lookup that not only reads META-INF/services but, for example, finds the requested service providers around the Internet, etc.
Lookup is a general purpose abstraction. While the JDK's ServiceLoader can de-facto have just one instance per classloader, there can be thousands of independent Lookup instances, each representing a single place to query services and interfaces. In fact this is exactly the way Lookup is used in NetBeans—it represents the context of each dialog, window element, node in a tree, etc.
For a four-part tutorial series that covers Lookup, see: