So I have a project in which I'm using Spring boot, and want to utilize a module system. I want the module system to be dynamically reloadable. I have it nearly working but @ComponentScan completely does not work in the modules.
There is a module folder containing jar files which are loaded at startup, and need to be dynamically unloaded, loaded, and reloaded.
The modules are created via AnnotationConfigApplicationContext, the context's classloader is set to the core's classloader, and a @Configuration class supplied by a method in the module interface is registered via context.register.
The @Bean declarations in the @Configuration work for autowire, and all the classes load properly. The problem is @ComponentScan doesn't work. I even tried annotating a class with @Component that has no field or anything, and it throws an autowire error like it's not in the context. This wouldn't be such a big deal if it wasn't also an issue with my repositories.
If there's a way I can manually run componentscan without the annotations I'm okay with doing that bit of extra work.
I've tried using the spring boot package with @SpringBootApplication(scanPackages = {"package.name"}
@EnableJpaRepository @EntityScan
are all in the appropriate places, and have correct parameters.
I tried using .register with the core context which didn't work. I can't really use that anyways, as you can de-register a configuration as far as I can tell.
This is my code that actually loads the jar file
public Module loadModule(Path path) throws Exception {
if (!path.toFile().exists()) {
throw new Exception(String.format("Could not find module at %s", path.toAbsolutePath()));
}
JarFile file = new JarFile(path.toFile());
ZipEntry moduleJson = file.getEntry("module.json");
System.out.println(path.toUri().toURL());
if (moduleJson == null) {
throw new Exception(String.format("Could not find module json at %s", path.toAbsolutePath()));
}
String moduleJsonSTR = CharStreams
.toString(new InputStreamReader(file.getInputStream(moduleJson), Charsets.UTF_8));
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting().create();
PluginConfig config = gson.fromJson(moduleJsonSTR, PluginConfig.class);
URLClassLoader classLoader = new URLClassLoader(new URL[] { path.toUri().toURL() },
getClass().getClassLoader());
Class mainClass = classLoader.loadClass(config.getMain());
Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()) {
JarEntry clazz = entries.nextElement();
if (clazz.getName().equals(mainClass.getName())) {
System.out.println("FOUND MAIN AND SKIPPING");
continue;
}
if (clazz.isDirectory() || !clazz.getName().endsWith(".class")) {
continue;
}
String className = clazz.getName().substring(0, clazz.getName().length() - 6);
className = className.replace('/', '.');
classLoader.loadClass(className);
}
Module module = (Module) mainClass.newInstance();
System.out.println(module.getConfigurationClass().getName());
module.setName(config.getName());
file.close();
classLoader.close();
return module;
}
This is my code that initializes the context
public AnnotationConfigApplicationContext initializeContext() {
SpringConfig cfg = getSpringConfig();
this.context = new AnnotationConfigApplicationContext();
this.context.setClassLoader(Core.class.getClassLoader());
this.context.refresh();
this.context.register(getConfigurationClass());
Map<String, Object> props = context.getEnvironment().getSystemProperties();
cfg.getProperties().forEach((key, value) -> props.put(key, value));
return context;
}
There's a bean that is a blank class with @Component being autowired into a class in which the context is autowired without problem. So I know autowire is working, I know it's spring managed, but @ComponentScan isn't working.
I'd like to either get ComponentScan working, or find a way to manually add the components programmatically.
More code:
Core Plugin: This is my module class: https://hastebin.com/potayuqali.java This is the controller which loads said modules: https://hastebin.com/ipegaqojiv.java Example Module:
This is an example of one of the modules: https://hastebin.com/umujiqepob.java This is the @configuration for that module: https://hastebin.com/lakemucifo.css