问题
I just read about Java 9 module system and I'd like to ask about ServiceLoader. Is there any way how to add service implementation when the application is already started? How about removing some service implementation?
Use case: I will have some application that calculates something. The calculation algorithm will be defined in some service(Java 9 module). Are there any steps that can be done to replace this algorithm without stopping the application? When will I replace the jars is it just that the calculation will fail and I will need to catch the error and restart when the module is done loading?
Is there any other project that can support such use case?
回答1:
Lets Assume BankController is your service . If you want to load its implementation dynamically from dynamic path,create a new module layer and load implementation.
private final BankController loadController(final BankConfig config) {
System.out.println("Loading bank with config : " + JSON.toJson(config));
try {
//Curent ModuleLayer is usually boot layer. but it can be different if you are using multiple layers
ModuleLayer currentModuleLayer = this.getClass().getModule().getLayer(); //ModuleLayer.boot();
final Set<Path> modulePathSet = Set.of(new File("path of implementation").toPath());
//ModuleFinder to find modules
final ModuleFinder moduleFinder = ModuleFinder.of(modulePathSet.toArray(new Path[0]));
//I really dont know why does it requires empty finder.
final ModuleFinder emptyFinder = ModuleFinder.of(new Path[0]);
//ModuleNames to be loaded
final Set<String> moduleNames = moduleFinder.findAll().stream().map(moduleRef -> moduleRef.descriptor().name()).collect(Collectors.toSet());
// Unless you want to use URLClassloader for tomcat like situation, use Current Class Loader
final ClassLoader loader = this.getClass().getClassLoader();
//Derive new configuration from current module layer configuration
final Configuration configuration = currentModuleLayer.configuration().resolveAndBind(moduleFinder, emptyFinder, moduleNames);
//New Module layer derived from current modulee layer
final ModuleLayer moduleLayer = currentModuleLayer.defineModulesWithOneLoader(configuration, loader);
//create new instance of Implementation, in this case org.util.npci.coreconnect.CoreController implements org.util.npci.api.BankController
final BankController bankController = ServiceLoader.load(moduleLayer, BankController.class);
return bankController;
} catch (Exception e) {BootLogger.info(e);}
return null;
}
来源:https://stackoverflow.com/questions/49644752/java-9-serviceloader-runtime-module-loading-and-replacement