我正在尝试使用反射来动态加载Log4j2库和方法。目标是让我的程序使用Log4j2,如果它在类路径中找到,并且只是在找不到Log4j2时登录到控制台。它适用于标准的日志方法,但我无法找到如何与供应商一起使用。
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.function.Supplier; // This java 8 interface happens to have the same signature as the Log4j2 Supplier interface
public class Test() {
public static void main(String[] args) {
try {
// Starting by loading Log4j2 classes and methods
ClassLoader classLoader = B.class.getClassLoader();
Class<?> classLogManager = classLoader.loadClass("org.apache.logging.log4j.LogManager");
Method methodGetLogger = classLogManager.getMethod("getLogger");
Class<?> interfaceSupplier = classLoader.loadClass("org.apache.logging.log4j.util.Supplier");
Object logger = methodGetLogger.invoke(null);
Method methodFatal = logger.getClass().getMethod("fatal", interfaceSupplier);
// Now trying an ugly trick, but it does not work
Supplier<String> fatalSupplier = new Supplier<String>() {
@Override
public String get() {
System.out.println("fatal log was evaluated");
return "fatal";
}
};
methodFatal.invoke(logger, fatalSupplier);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我当然得到以下错误:
java.lang.IllegalArgumentException: argument type mismatch
有没有办法创建一个匹配Supplier接口(Log4j)的对象而不静态加载任何Log4j2类?
答案 0 :(得分:1)
我建议您使用现有的抽象日志层,而不是实现自己的抽象日志记录层,例如:
这两种方法都可以满足您的需求,即只需更改类路径上的.jar文件即可替换实际日志库。
答案 1 :(得分:1)
你打算如何使用它?
使用反射调用记录器不会很漂亮。如果您的目标是创建抽象,那么最简单的方法就是创建自己的接口,然后创建一个使用Log4j 2的实现,而另一个实现则不创建。然后创建一个工厂,在类路径上检查Log4j 2,然后根据该工具将正确的实现绑定到您的应用程序。然后可以直接针对Log4j 2编写适配器代码。
但我也同意 - 为什么不使用SLF4J或Commons Logging?
答案 2 :(得分:1)
失败的原因是java.util.function.Supplier
不是org.apache.logging.log4j.util.Supplier
的子类型。
替换
行methodFatal.invoke(logger, fatalSupplier);
通过
Object newProxyInstance = Proxy.newProxyInstance(classLoader, new Class[]{interfaceSupplier}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//TODO check method
return fatalSupplier.get();
}
});
methodFatal.invoke(logger, newProxyInstance);