У меня есть первый плагин, который служит в качестве API для других моих плагинов. Этот плагин имеет собственный контекст Spring. Я начал разработку второго плагина, который должен извлекать bean-компоненты из первого плагина и добавлять их в свой собственный контекст. В данном случае это пул соединений HikariCP.
Для управления контекстами моих плагинов я создал интерфейс PluginContextManager, который содержит следующий код:
Код: Выделить всё
import lombok.NonNull;
import lombok.val;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static com.github.badpop.hildir.common.colors.HildirColors.LOG_COLOR;
import static net.kyori.adventure.text.Component.text;
/**
* Utility interface used to build a plugin's context in order to take advantage of dependency injection.
*/
public interface PluginContextManager {
/**
* Constructs an instance of a PluginContext which will allow dependencies to be injected.
*
* @param plugin the main class of the plugin (the one that extends JavaPlugin).
* @param customBeans an iterable containing all the customs beans to be added to the context
* @param componentClasses Register one or more component classes to be processed.
* @param the main class of the plugin (the one that extends JavaPlugin).
* @return a new JavaPlugin instance
*/
static PluginContext buildPluginContext(@NotNull @NonNull T plugin,
@Nullable Iterable... componentClasses) {
return new PluginContext(plugin, customBeans, componentClasses);
}
/**
* Constructs an instance of a PluginContext which will allow dependencies to be injected.
*
* @param plugin the main class of the plugin (the one that extends JavaPlugin).
* @param customBeans an iterable containing all the customs beans to be added to the context
* @param componentClasses Register one or more component classes to be processed.
* @param the main class of the plugin (the one that extends JavaPlugin).
* @return a new JavaPlugin instance
*/
static PluginContext buildPluginContext(@NotNull @NonNull T plugin,
@Nullable Iterable... componentClasses) {
return new PluginContext(plugin, customBeans, parentContext, componentClasses);
}
class PluginContext extends AnnotationConfigApplicationContext {
private PluginContext(T plugin, Iterable... componentClasses) {
super();
plugin.getComponentLogger().info(text("Building %s context...".formatted(plugin.toString())).color(LOG_COLOR));
setDisplayName(plugin + " plugin context");
val beanFactory = getBeanFactory();
beanFactory.registerSingleton("plugin", plugin);
beanFactory.registerSingleton("logger", plugin.getComponentLogger());
if (customBeans != null) {
customBeans.forEach(customBean -> beanFactory.registerSingleton(customBean.beanName(), customBean.beanInstance()));
}
register(componentClasses);
refresh();
plugin.getComponentLogger().info(text("%s context successfully built !".formatted(plugin.toString())).color(LOG_COLOR));
}
private PluginContext(T plugin, Iterable... componentClasses) {
super();
plugin.getComponentLogger().info(text("Building %s context...".formatted(plugin.toString())).color(LOG_COLOR));
setDisplayName(plugin + " plugin context");
setId(plugin.getName() + "_plugin_context");
setParent(parentContext);
val beanFactory = getBeanFactory();
beanFactory.registerSingleton("plugin", plugin);
beanFactory.registerSingleton("logger", plugin.getComponentLogger());
if (customBeans != null) {
customBeans.forEach(customBean -> beanFactory.registerSingleton(customBean.beanName(), customBean.beanInstance()));
}
register(componentClasses);
refresh();
plugin.getComponentLogger().info(text("%s context successfully built !".formatted(plugin.toString())).color(LOG_COLOR));
}
}
record CustomBean(String beanName, T beanInstance) {
}
}
Во втором плагине я хочу определить контекст первого плагина как родительский для его контекста:
Код: Выделить всё
//Retrieve the first plugin main class
val hildirApi = (HildirApi) Bukkit.getServer().getPluginManager().getPlugin("hildir-api");
if (hildirApi == null) {
getComponentLogger().error(text("Unable to enable hildir-people... Is the hildir-api plugin installed ?").color(RED));
getServer().getPluginManager().disablePlugin(this);
}
//setting the first plugin's context as parent of the new context
peopleContext = PluginContextManager.buildPluginContext(this, emptyList(), hildirApi.getContext(), HildirPeopleConfiguration.class);
Код: Выделить всё
//A bean of type HikariConnectionPool is already present in the parent context
@Bean
public TestCommand testCommand(HikariConnectionPool hikariConnectionPool) {
return new TestCommand(hikariConnectionPool);
}
Код: Выделить всё
[20:43:25 ERROR]: Error occurred while enabling hildir-people v1.0.0-SNAPSHOT (Is it up to date?)
java.lang.LinkageError: loader constraint violation: loader 'hildir-people-1.0.0-SNAPSHOT.jar' @29b08d69 wants to load class com.github.badpop.hildir.common.dependencyinjection.PluginContextManager$PluginContext. A different class with the same name was previously loaded by 'hildir-api-1.0.0-SNAPSHOT.jar' @77c05f35. (com.github.badpop.hildir.common.dependencyinjection.PluginContextManager$PluginContext is in unnamed module of loader 'hildir-api-1.0.0-SNAPSHOT.jar' @77c05f35, parent loader java.net.URLClassLoader @421faab1)
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
at java.lang.ClassLoader.defineClass(ClassLoader.java:1027) ~[?:?]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) ~[?:?]
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:243) ~[paper-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:593) ~[?:?]
at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:169) ~[paper-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.PluginClassLoader.loadClass(PluginClassLoader.java:164) ~[paper-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:526) ~[?:?]
at com.github.badpop.hildir.common.dependencyinjection.PluginContextManager.buildPluginContext(PluginContextManager.java:46) ~[hildir-people-1.0.0-SNAPSHOT.jar:?]
at com.github.badpop.hildirpeople.HildirPeople.buildPluginContext(HildirPeople.java:58) ~[hildir-people-1.0.0-SNAPSHOT.jar:?]
at com.github.badpop.hildirpeople.HildirPeople.onEnable(HildirPeople.java:42) ~[hildir-people-1.0.0-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:287) ~[paper-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:188) ~[paper-1.20.4.jar:git-Paper-496]
at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.enablePlugin(PaperPluginManagerImpl.java:104) ~[paper-1.20.4.jar:git-Paper-496]
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:507) ~[paper-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_20_R3.CraftServer.enablePlugin(CraftServer.java:639) ~[paper-1.20.4.jar:git-Paper-496]
at org.bukkit.craftbukkit.v1_20_R3.CraftServer.enablePlugins(CraftServer.java:550) ~[paper-1.20.4.jar:git-Paper-496]
at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:671) ~[paper-1.20.4.jar:git-Paper-496]
at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:431) ~[paper-1.20.4.jar:git-Paper-496]
at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:309) ~[paper-1.20.4.jar:git-Paper-496]
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1131) ~[paper-1.20.4.jar:git-Paper-496]
at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:319) ~[paper-1.20.4.jar:git-Paper-496]
at java.lang.Thread.run(Thread.java:1583) ~[?:?]
Как мы можем гарантировать, что один контекст Spring зависит от другого для совместного использования bean-компонентов?
Подробнее здесь: https://stackoverflow.com/questions/785 ... to-share-b