我在我的 spigot 插件中使用 Guice 的辅助注入时遇到问题,并且似乎无法缩小问题范围。这是我得到的错误:
> [12:00:38 INFO]: [DestinyMC] Enabling DestinyMC v1.0
> 2019-01-14 12:00:41,492 Log4j2-TF-1-AsyncLogger[AsyncContext@5c647e05]-1 ERROR An exception occurred processing Appender File com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: zip file closed
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2217)
at com.google.common.cache.LocalCache.get(LocalCache.java:4154)
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4158)
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5147)
at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:5153)
at com.google.inject.internal.util.StackTraceElements.forMember(StackTraceElements.java:71)
at com.google.inject.internal.Messages.formatSource(Messages.java:241)
at com.google.inject.internal.Messages.formatSource(Messages.java:220)
at com.google.inject.internal.Messages.formatMessages(Messages.java:90)
at com.google.inject.CreationException.getMessage(CreationException.java:50)
at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:134)
at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:122)
at org.apache.logging.log4j.core.async.RingBufferLogEvent.getThrownProxy(RingBufferLogEvent.java:330)
at org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter.format(ExtendedThrowablePatternConverter.java:61)
at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:38)
at org.apache.logging.log4j.core.layout.PatternLayout$PatternSelectorSerializer.toSerializable(PatternLayout.java:455)
at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:232)
at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:217)
at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:57)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:177)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:170)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:161)
at org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender.append(RollingRandomAccessFileAppender.java:218)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:448)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:433)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:79)
at org.apache.logging.log4j.core.async.AsyncLogger.actualAsyncLog(AsyncLogger.java:337)
at org.apache.logging.log4j.core.async.RingBufferLogEvent.execute(RingBufferLogEvent.java:161)
at org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:45)
at org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:29)
at com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:168)
at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:125)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: zip file closed
at java.util.zip.ZipFile.ensureOpen(Unknown Source)
at java.util.zip.ZipFile.getEntry(Unknown Source)
at java.util.jar.JarFile.getEntry(Unknown Source)
at java.util.jar.JarFile.getJarEntry(Unknown Source)
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:120)
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:104)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:49)
at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:45)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3716)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2424)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2298)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2211)
... 39 more
这是我的活页夹类:
public class MainBinder extends AbstractModule {
@Override
protected void configure() {
bind(DestinyMC.class).toInstance(this.plugin);
install(new FactoryModuleBuilder().build(InventoryFromFileFactory.class));
}
当我注释掉安装行时,错误消失了。那条线使用这个工厂类
public interface InventoryFromFileFactory {
InventoryFromFile create(String targetRootKey, String targetFile);
}
其中声明了在创建此类对象时需要手动提供的参数:
public class InventoryFromFile {
@Inject
public InventoryFromFile
(
@Assisted String targetRootKey,
@Assisted String targetFile,
ConfigAccessorFactory configAccessorFactory
)
{
ConfigurationSection targetCS = configAccessorFactory.create(targetFile).getCustomConfig().getConfigurationSection(targetRootKey);
...
}
}
这ConfigAccessFactory
是另一个辅助注入的工厂类
public interface ConfigAccessorFactory {
ConfigAccessor create(String filename);
}
在这里使用:
public class ConfigAccessor {
private Plugin plugin;
private final String customFileName;
@Inject
public ConfigAccessor
(
@Assisted String fileName,
DestinyMC plugin
)
{
this.customFileName = fileName;
this.plugin = plugin;
}
...
}
最后,DestinyMC
依赖是 spigot 插件的主类:
public class DestinyMC extends JavaPlugin {
//Inject dependencies
@Inject private ConfigAccessorFactory configAccessorFactory;
//Code only run once when the plugin is enabled
public void onEnable() {
MainBinder mainBinder = new MainBinder(this);
Injector injector = Guice.createInjector(mainBinder);
injector.injectMembers(this);
//Saves config files to disk if they don't exist
saveDefaultConfig();
Arrays.asList(
"inventory-gui.yml",
"player-tree-template.yml",
"player-tree-data.yml"
).forEach((file) -> {
configAccessorFactory.create(file).saveDefaultConfig();
});
...
}
我不太确定我做错了什么,但我对 Guice 还很陌生,所以我很可能误解了一些东西。另外,如果有更好的方法可以做到这一点,请告诉我。谢谢您的帮助。