I am trying to use Service loader to load all the implementations of an Interface. However I am not unable get it working when Service implementation has private fields.
Here are my service and implementation setup.
public interface OrderProcessor {
void process()
}
And in implentation, I need this field to be initialised.
public class OrderProcessorImpl implements OrderProcessor {
private final int maxOrders;
public OrderStreamProcessorImpl(int maxOrders) {
this.maxOrders = maxOrders;
}
@Override
public void process() throws IOException {
// Logic which involves maxOrders.
}
}
Here's how I am trying to load this service using ServiceLoaderAPI.
public OrderProcessor createProcessor(int maxOrders) {
var factories =
ServiceLoader.load(OrderProcessor.class);
if(factories.hasNext()){
return factories.next();
} else {
throw new IllegalStateException("No OrderProcessor found");
}
}
I also tried using
public static OrderProcessorImpl provider()
but this doesnt work with params.
How do I solve this issue ? Or ServiceLoader API is not the right option in this use case?
Thanks
You have missed out a factory interface which enables the service to create instances of an order processor. See details of ServiceLoader.
You would need two interfaces defining the service, for the factory and a processor. The ServiceLoader will provide instances of all registered Factory implementations:
public interface OrderProcessor {
void process() throws IOException;
}
public interface OrderProcessorFactory {
OrderProcessor createProcessor(int maxOrders);
}
Then you can implement 2 classes supporting the factory and processor:
public class OrderProcessorFactoryImpl implements OrderProcessorFactory {
public OrderProcessorFactoryImpl() {
System.out.println("OrderProcessorFactoryImpl()");
}
public OrderProcessor createProcessor(int maxOrders)
{
System.out.println("OrderProcessorFactoryImpl.createProcessor("+maxOrders+")");
return new OrderProcessorImpl(maxOrders);
}
}
public class OrderProcessorImpl implements OrderProcessor {
private final int maxOrders;
public OrderProcessorImpl(int maxOrders) {
System.out.println("OrderProcessorImpl("+maxOrders+")");
this.maxOrders = maxOrders;
}
@Override
public void process() throws IOException {
System.out.println("OrderProcessorImpl.process() where maxOrders is "+maxOrders);
}
}
Add a file META-INF/services/packagenameof.theinterface.OrderProcessorFactory
to register your implementation which contains one line:
yourpackage.OrderProcessorFactoryImpl
Then you can lookup a factory and instantiate an order processor:
ServiceLoader<OrderProcessorFactory> loader = ServiceLoader.load(OrderProcessorFactory.class);
System.out.println("loader="+loader);
for (OrderProcessorFactory factory : loader) {
OrderProcessor max999 = factory.createProcessor(999);
System.out.println("max999="+max999);
if (max999 != null)
max999.process();
}
Should print:
loader=java.util.ServiceLoader[stackoverflow.service.OrderFactory]
OrderFactoryImpl()
OrderFactoryImpl.createProcessor(999)
OrderProcessorImpl(999)
max999=yourpackage.OrderProcessorImpl@7699a589
OrderProcessorImpl.process maxOrders=999