如何使用反射调用外部 jar 中的方法

How to invoke a method inside a external jar using reflection

我想通过反射调用外部 .jar 中的方法。

这是 jar 中的示例代码。

public class HelloFunction implements Runnable, RequestHandler<Request> {

    @Override
    public void handle(final Request request) {
        System.out.println("handle : " + request);
    }

    @Override
    public void run() {
        System.out.println("run......");
    }
}

然后我将这个 jar 加载到一个单独的 java 程序中并尝试调用 HelloFunction.handle() 方法。这是该部分的示例代码。

public class App {

    public static void main(String[] args) {
        test();
    }

    public static void test(){

        try{

            final Class<?> functionClass = getClassFromFunctionJar("com.hello.HelloFunction");

            final Object functionClassObject = functionClass.newInstance();

            if(functionClassObject instanceof RequestHandler){

                @SuppressWarnings("unchecked")
                final RequestHandler<Object> handler = RequestHandler.class.cast(functionClassObject);

                final Object inputObject = getRequestClass(functionClass).newInstance();

                handler.handle(inputObject);


            }

        }catch(final Exception e){

            System.err.println(e.getMessage());

        }
    }

    public static Class<?> getRequestClass(final Class<?> cls) throws FunctionInvokerException{

        try{
            final Type[] types = cls.getGenericInterfaces();

            for(Type type : types){

                //check RequestHandler
                if(type.getTypeName().contains(RequestHandler.class.getName())){

                    final ParameterizedType parameterizedType = (ParameterizedType) type;

                    // [0]=> Request Type
                    final String inputClassName = parameterizedType.getActualTypeArguments()[0].getTypeName();
                    return getClassFromFunctionJar(inputClassName);

                }

            }

            throw new Exception("UNABLE_TO_FIND_REQUEST_TYPE");

        }catch(final Exception e){
            throw new FunctionInvokerException(e);
        }

    }

    private static Class<?> getClassFromFunctionJar(final String className) throws ClassNotFoundException, MalformedURLException{
        final ClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new URL("file:" + "/jar-location/hello.jar")}, App.class.getClassLoader());
        return Class.forName(className, true, classLoader);
    }

}

你可以在这里看到我使用 getClassFromFunctionJar() 方法从 jar 加载 Class。 getRequestClass() 方法用于查找 HelloFunction.handle() 方法的输入参数的 class 类型。 在调用 handle() 方法之前一切都很好。

最后我得到一个错误 "com.hello.Request cannot be cast to com.hello.Request"。你能帮我解决这个问题吗?

由不同 class 加载程序加载的相同 class 定义被 JVM 视为两个不同的 classes。

你的代码 "URLClassLoader.newInstance" 同时获得不同的 class 加载程序

第一个(处理程序#参数)是:URLClassLoader#1 & com.hello.Request

第二个(inputObject)是:URLClassLoader#2 & com.hello.Request

"com.hello.Request cannot be cast to com.hello.Request"。

实际错误是

"URLClassLoader#2 com.hello.Request cannot be cast to URLClassLoader#1 com.hello.Request"

并建议:

private static final ClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new URL("file:" + "/jar-location/hello.jar")}, App.class.getClassLoader());

private static Class<?> getClassFromFunctionJar(final String className) throws ClassNotFoundException, MalformedURLException{
    return Class.forName(className, true, classLoader);
}