onEnable 之前加载插件

修复 NoClassDefFoundError 的问题
This commit is contained in:
Izzel_Aliz 2018-04-21 13:58:56 +08:00
parent b941cac63f
commit 2edca32b89
8 changed files with 135 additions and 40 deletions

View File

@ -14,7 +14,8 @@ import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.ow2.asm:asm:6.1.1") @Dependency(type = Dependency.Type.LIBRARY, maven = "org.ow2.asm:asm:6.1.1")
@Dependency(type = Dependency.Type.LIBRARY, maven = "com.zaxxer:HikariCP:3.0.0") @Dependency(type = Dependency.Type.LIBRARY, maven = "com.zaxxer:HikariCP:3.1.0")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.slf4j:slf4j-api:1.7.25")
public class TLib { public class TLib {
private static TLib tLib; private static TLib tLib;

View File

@ -1,5 +1,7 @@
package com.ilummc.tlib.annotations; package com.ilummc.tlib.annotations;
import com.ilummc.tlib.util.Ref;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -20,6 +22,6 @@ public @interface Config {
boolean listenChanges() default false; boolean listenChanges() default false;
int excludeModifiers() default Modifier.STATIC | Modifier.TRANSIENT; int excludeModifiers() default Modifier.STATIC | Modifier.TRANSIENT | Ref.ACC_SYNTHETIC | Ref.ACC_BRIDGE;
} }

View File

@ -3,6 +3,7 @@ package com.ilummc.tlib.inject;
import com.ilummc.tlib.TLib; import com.ilummc.tlib.TLib;
import com.ilummc.tlib.annotations.*; import com.ilummc.tlib.annotations.*;
import com.ilummc.tlib.dependency.TDependency; import com.ilummc.tlib.dependency.TDependency;
import com.ilummc.tlib.util.Ref;
import com.ilummc.tlib.util.TLogger; import com.ilummc.tlib.util.TLogger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -14,22 +15,10 @@ import java.lang.reflect.Field;
public class DependencyInjector { public class DependencyInjector {
public static void inject(Plugin plugin, Object o) { public static void inject(Plugin plugin, Object o) {
try {
injectLogger(plugin, o); injectLogger(plugin, o);
} catch (NoClassDefFoundError ignored) {
}
try {
injectConfig(plugin, o); injectConfig(plugin, o);
} catch (NoClassDefFoundError ignored) {
}
try {
injectPluginInstance(plugin, o); injectPluginInstance(plugin, o);
} catch (NoClassDefFoundError ignored) {
}
try {
injectDependencies(plugin, o); injectDependencies(plugin, o);
} catch (NoClassDefFoundError ignored) {
}
} }
static void injectOnEnable(Plugin plugin) { static void injectOnEnable(Plugin plugin) {
@ -48,7 +37,7 @@ public class DependencyInjector {
} }
private static void ejectConfig(Plugin plugin, Object o) { private static void ejectConfig(Plugin plugin, Object o) {
for (Field field : o.getClass().getDeclaredFields()) { for (Field field : Ref.getDeclaredFields(o.getClass())) {
Config config; Config config;
if ((config = field.getType().getAnnotation(Config.class)) != null) { if ((config = field.getType().getAnnotation(Config.class)) != null) {
try { try {
@ -64,7 +53,7 @@ public class DependencyInjector {
} }
private static void injectConfig(Plugin plugin, Object o) { private static void injectConfig(Plugin plugin, Object o) {
for (Field field : o.getClass().getDeclaredFields()) { for (Field field : Ref.getDeclaredFields(o.getClass())) {
try { try {
Config config; Config config;
if ((config = field.getType().getAnnotation(Config.class)) != null) { if ((config = field.getType().getAnnotation(Config.class)) != null) {
@ -100,7 +89,7 @@ public class DependencyInjector {
} }
private static void injectLogger(Plugin plugin, Object o) { private static void injectLogger(Plugin plugin, Object o) {
for (Field field : o.getClass().getDeclaredFields()) { for (Field field : Ref.getDeclaredFields(o.getClass())) {
try { try {
Logger logger; Logger logger;
if ((logger = field.getAnnotation(Logger.class)) != null) { if ((logger = field.getAnnotation(Logger.class)) != null) {
@ -116,7 +105,7 @@ public class DependencyInjector {
} }
private static void injectPluginInstance(Plugin plugin, Object o) { private static void injectPluginInstance(Plugin plugin, Object o) {
for (Field field : o.getClass().getDeclaredFields()) { for (Field field : Ref.getDeclaredFields(o.getClass())) {
try { try {
PluginInstance instance; PluginInstance instance;
if ((instance = field.getAnnotation(PluginInstance.class)) != null) { if ((instance = field.getAnnotation(PluginInstance.class)) != null) {

View File

@ -49,9 +49,7 @@ public class TLibPluginManager implements PluginManager {
@Override @Override
public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException {
Plugin plugin = instance.loadPlugin(file); return instance.loadPlugin(file);
DependencyInjector.injectOnEnable(plugin);
return plugin;
} }
@Override @Override
@ -94,6 +92,7 @@ public class TLibPluginManager implements PluginManager {
@Override @Override
public void enablePlugin(Plugin plugin) { public void enablePlugin(Plugin plugin) {
DependencyInjector.injectOnEnable(plugin);
instance.enablePlugin(plugin); instance.enablePlugin(plugin);
} }

View File

@ -0,0 +1,18 @@
package com.ilummc.tlib.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class IO {
public static byte[] readFully(InputStream inputStream) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = inputStream.read(buf)) > 0) {
stream.write(buf, 0, len);
}
return stream.toByteArray();
}
}

View File

@ -0,0 +1,59 @@
package com.ilummc.tlib.util;
import com.ilummc.tlib.util.asm.AsmAnalyser;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import javax.annotation.concurrent.ThreadSafe;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@ThreadSafe
public class Ref {
private static final Map<String, List<Field>> cachedFields = new ConcurrentHashMap<>();
public static final int ACC_BRIDGE = 0x0040;
public static final int ACC_SYNTHETIC = 0x1000;
public static List<Field> getDeclaredFields(Class<?> clazz) {
return getDeclaredFields(clazz, 0, false);
}
public static List<Field> getDeclaredFields(String clazz, int excludeModifiers, boolean cache) {
try {
return getDeclaredFields(Class.forName(clazz), excludeModifiers, cache);
} catch (ClassNotFoundException e) {
return Collections.emptyList();
}
}
public static List<Field> getDeclaredFields(Class<?> clazz, int excludeModifiers, boolean cache) {
try {
Class.forName("org.objectweb.asm.ClassVisitor");
List<Field> fields;
if ((fields = cachedFields.get(clazz.getName())) != null) return fields;
ClassReader classReader = new ClassReader(clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class"));
AsmAnalyser analyser = new AsmAnalyser(new ClassWriter(ClassWriter.COMPUTE_MAXS), excludeModifiers);
classReader.accept(analyser, ClassReader.SKIP_DEBUG);
fields = analyser.getFields().stream().map(name -> {
try {
return clazz.getDeclaredField(name);
} catch (Throwable ignored) {
}
return null;
}).filter(Objects::nonNull).collect(Collectors.toList());
if (cache) cachedFields.putIfAbsent(clazz.getName(), fields);
return fields;
} catch (Exception e) {
return Collections.emptyList();
}
}
}

View File

@ -0,0 +1,31 @@
package com.ilummc.tlib.util.asm;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.List;
public class AsmAnalyser extends ClassVisitor implements Opcodes {
private final List<String> fields = new ArrayList<>();
private final int excludeModifier;
public AsmAnalyser(ClassVisitor classVisitor, int excludeModifiers) {
super(Opcodes.ASM6, classVisitor);
this.excludeModifier = excludeModifiers;
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if ((access & excludeModifier) == 0)
fields.add(name);
return super.visitField(access, name, descriptor, signature, value);
}
public List<String> getFields() {
return fields;
}
}

View File

@ -51,21 +51,6 @@ import java.util.Random;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class Main extends JavaPlugin implements Listener { public class Main extends JavaPlugin implements Listener {
public Main() {
super();
inst = this;
disable = false;
TLib.injectPluginManager();
// 载入配置
saveDefaultConfig();
// 加载依赖
TLib.init();
}
@Getter @Getter
private static Plugin inst; private static Plugin inst;
@Getter @Getter
@ -116,6 +101,17 @@ public class Main extends JavaPlugin implements Listener {
@Override @Override
public void onLoad() { public void onLoad() {
inst = this;
disable = false;
TLib.injectPluginManager();
// 载入配置
saveDefaultConfig();
// 加载依赖
TLib.init();
// 载入目录 // 载入目录
setupDataFolder(); setupDataFolder();
// 注册配置 // 注册配置