How to implement the API/SPI Pattern in Java? -


I am developing a framework that exposes the API to developers:

  Public Interface MyAPI {Public Zero doSomeStuff (); Public int getWidgets (boolean herran); } All developers should code their projects against these API methods. I also enable them to keep separate "driver" / "API bindings" on runtime classpath (similarly on JDBC or SLF 4J work) and for API method call ( doSomeStuff () , etc. I want to.) Work on various third party resources (files, servers, whatever). In this way, the same code and API call will mapping to handle different resources / movement / binding runtime watches the class path (i.e.  myapi-ftp ,  myapi-ssh ,  IAPI-teleportation ).  

How can I write an SPI (and package) that calls for a runtime binding, and map MyAPI correct (solid) implementation ? In other words, if myapi-ftp allows you to get getWidgets (boolean) from an FTP server, how can I pick it up (both APIs and SPIs To use) )?

Bonus points for concrete, Java code examples are working! thank you in advanced!

Take a look at the java.util.ServiceLoader class.

In general, this idea is:

API Jar

  • Provide Interface
  • Service Use the loader class to see the implementation

    binding / driver jar

  • Implement the interface
  • File the Meta-INF

    API jar
      package com. Foo; Public interface FooInterface {...} Public Category FooInterfaceFactory {Public Static FooInterface newFooInstance () {ServiceLoader & lt; FooInterface & gt; Loader = ServiceLoader.load (FooInterface.class); Iterator & LT; FooInterface & gt; This = loader Director (); // Choose one of the implementations provided and return it. }   

    binding jar
      package com.myfoo; Public class MyFooImpl implements FooInterface {...} Meta-INF / com.foo.FooInterface com.myfoo.MyFooImpl   

    Edit

    SPI example
      acknowledges the public interface FooSpi {void (string URL); FooInterface getFooInstance (); } Public class FooInterfaceFactory {Public Static FooInterface getFooInterfaceInstance (string URL) {ServiceLoader & lt; FooSpi & gt; Loader = ServiceLoader.load (FooSpi.class); Iterator & LT; FooSpi & gt; This = loader Director (); While (this haas next ()) {fuspi fuspi = it.NX (); If (fooSpi .ccepts (url)) {return fooSpi.getFooInstance (); }} Return tap; }}   

    And of course, change the file name to com.foo.FooSpi and provide implementation of FooSpi. This will allow you to isolate the public API from the SPI interface.

    If you want to hide the acceptance method, you can always have a second interface which is your public API, and T

  • Comments