Java 如何使用带有反射的动态加载接口?

Java 如何使用带有反射的动态加载接口?,java,reflection,Java,Reflection,我试图使用反射动态加载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

我试图使用反射动态加载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();
        }
    }

}

有没有办法在不静态加载任何Log4j2类的情况下创建与供应商接口(Log4j接口)匹配的对象?

我建议您使用现有的抽象日志层,而不是实现自己的抽象日志层,例如:

  • 带(推荐)

这两种方法都可以满足您的需要,即只需更改类路径上的.jar文件即可替换实际的日志库。

您打算如何使用它

使用反射来调用记录器不会很好。如果您的目标是创建一个抽象,那么最简单的方法就是创建您自己的接口,然后创建一个使用log4j2的实现和另一个不使用log4j2的实现。然后创建一个工厂,检查类路径上的log4j2,然后基于此将正确的实现绑定到应用程序。然后可以直接针对log4j2编写适配器代码


但我也同意-为什么不使用SLF4J或Commons日志记录?

失败的原因是
java.util.function.Supplier
不是
org.apache.Logging.log4j.util.Supplier
的子类型

更换线路

methodFatal.invoke(logger, fatalSupplier);


谢谢!这正是我想要的。我将仔细阅读关于这些我不知道的类的文档。不使用SLF4J或通用日志主要是因为不知道它们。。。现在我必须检查他们能做什么,也许他们会非常适合。谢谢,我不知道这些工具,也许我会使用其中一个,而不是写我自己的工具。
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);