简体   繁体   中英

Best practices for runtime-only dependencies in OSGi

In line with the Open-Closed Principle , I typically design my Java packages and libraries in such a way that there is a generic "interface" or "API" package/library and one or more implementations (quite similar to many common APIs like JDBC or JAXP/SAX). To locate an implementation (or sometimes multiple implementations) in the base API library without violating OCP, I commonly use Java's ServiceLoader mechanism, or occasionally classpath scanning via third-party libraries like ClassGraph or Reflections . From a Maven perspective, the implementations are brought in as runtime dependencies (as they're only needed at execution time, but not at compile time). Pretty standard stuff.

So, now, I want to make some of these packages available as OSGi bundles (with API and implementation in separate bundles), but since in OSGi each bundle has its own class loader, neither classpath scanning nor the ServiceLoader API will work for this purpose. At first glance, OSGi's "fragment" mechanism seems to be the closest equivalent to the plain-Java setup described above. In that scenario, the API bundle would be the "fragment host", and concrete implementations would attach as fragments to that host bundle. As the fragment host and all its attached fragments use the same class loader, the standard plain-Java mechanisms like ServiceLoader or ClassGraph would conceivably still work. This would also have the advantage that there would be no need to detect whether a library/bundle is running in an OSGi context or not, and no OSGi framework dependencies are needed.

So, in a nutshell, my question is: are fragments the correct way to implement runtime-only dependencies in OSGi or is there a better (or more standard) way? Preferably, I'm looking for a solution that works in an OSGi container but does not require a dependency on OSGi itself.

No Fragments are almost always wrong outside the translations. The OSGi model is to use services .

The way to go then is to use DS. Using bnd (in maven, gradle, ant, sbt, or Bndtools) you can create components . A component is a Plain Old Java Object (POJO) that is annotated with injection and activation instructions. You could make those components to take all its dependencies in the constructor.

The bnd code uses the annotations to generate an XML file that is used in runtime to create, activate, inject, and register those components. This will then work out of the box in an OSGi Framework. The annotations are build time so they do not create dependencies in your runtime.

In your non-OSGi environment, you'd be responsible to call that constructor yourself. So you gather your dependencies using the Service Loader and then construct them in the right order.

@Component
public class MyComponent implements Foo {

      final Bar bar;

      @Activate
      public MyComponent( @Reference Bar bar ) {
        this.bar = bar;
      }
      ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM