I am currently working on a project which includes running Spring Boot within a Minecraft Spigot / Paper plugin.
My project is setup to run a custom Framework that I built on plugin initialization:
// MyPlugin class
override fun onEnable() {
MyFramework.run(javaClass, name)
}
My framework is responsible for initializing the Spring application, which works fine...
Dependency injection and any other part of Spring itself works without problems, but one thing bothers me.
I can't get the application.properties
file to work with Spring Boot.
Spring seems to just ignore my properties file and any other external configuration file, when declared in my Minecraft plugin....
I have tried multiple things already:
Custom resource loader when building the Spring Application using SpringApplicationBuilder
Setting the properties file location using spring.config.location
when building the application using SpringApplicationBuilder
Adding @PropertySources
to the main class of my Spring Application
Manually adding the application.properties file to the output JAR ROOT before running
I have made sure that the configuration file is correctly placed in the ROOT directory of my plugin.
The file is also found by the application proven by the following test:
public static void checkPropertiesFile() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource("application.properties");
if (resource != null) {
System.out.println("Found application.properties at " + resource.getPath());
} else {
System.out.println("application.properties not found in classpath.");
}
}
This is the code snippet relevant to running the spring application:
public static void run(Class<?> plugin, String pluginName) {
final ClassLoader pluginClassLoader = plugin.getClassLoader();
// needed or else spring startup fails
Thread.currentThread().setContextClassLoader(pluginClassLoader);
final ResourceLoader loader = new DefaultResourceLoader(pluginClassLoader);
final SpringApplicationBuilder builder = new SpringApplicationBuilder();
// auto generated "main spring class"
// needed since when using the actual plugin main class, spring tries to instantiate a new instance of our plugin class, which fails
final Class<?> pluginConfiguration = Class.forName(plugin.getPackageName() + ".PluginConfiguration");
final Class<?>[] sources = {pluginConfiguration, SpigotConfiguration.class, BungeecordConfiguration.class};
context = builder.sources(sources)
.initializers(applicationContext -> {
applicationContext.setClassLoader(pluginClassLoader);
})
.resourceLoader(loader)
.properties("plugin.name=" + pluginName)
.properties("plugin.main=" + plugin.getName())
.run();
}
I am really lost here, you guys are my last hope, I am slowly losing my mind
I have found a way to kind of resolve my issue.
When telling Spring to use „StandardEnvironment“ while building, Spring picks up any System Property set before starting:
builder.initializers(applicationContext -> {
applicationContext.setEnvironment(new StandardEnvironment());
})
Now I can use @mlecz s suggestion (Loading the application.properties with a Properties
Object and iterating over every key-value pair, then setting a System Property for every pair).
This is a workaround and not directly the functionality I was hoping for, but it works.
Here’s the edited code snippet for anyone having similar issues with implementing Spring in such an environment:
public static void run(Class<?> plugin, String pluginName) {
final ClassLoader pluginClassLoader = plugin.getClassLoader();
// needed or else spring startup fails
Thread.currentThread().setContextClassLoader(pluginClassLoader);
final ResourceLoader loader = new DefaultResourceLoader(pluginClassLoader);
final SpringApplicationBuilder builder = new SpringApplicationBuilder();
final Class<?> pluginConfiguration = Class.forName(plugin.getPackageName() + ".PluginConfiguration");
final Class<?>[] sources = {pluginConfiguration, SpigotConfiguration.class, BungeecordConfiguration.class};
System.setProperty("plugin.name", pluginName);
System.setProperty("plugin.main", plugin.getName());
try {
final Properties properties = new Properties();
properties.load(pluginClassLoader.getResourceAsStream("application.properties"));
properties.forEach((key, value) -> {
System.setProperty(key.toString(), value.toString());
});
} catch (Exception ignored) {}
context = builder.sources(sources)
.initializers(applicationContext -> {
applicationContext.setClassLoader(pluginClassLoader);
// this somehow enables spring to pickup the system properties
applicationContext.setEnvironment(new StandardEnvironment());
})
.resourceLoader(loader)
.run();
}
With this implementation I was able to set my active profile with the „application.properties“ which is located in the ROOT of my built JAR