【问题标题】:How to invoke a method inside a external jar using reflection如何使用反射调用外部 jar 中的方法
【发布时间】:2018-05-08 04:41:37
【问题描述】:

我想通过使用反射来调用外部 .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() 方法的输入参数的类类型。 在调用 handle() 方法之前一切都很好。

最后我得到一个错误,上面写着“com.hello.Request 不能转换为 com.hello.Request”。你能帮我解决这个问题吗?

【问题讨论】:

  • 为什么需要反思?
  • com.hello.Request cannot be cast to com.hello.Request ALWAYS 表示您已经通过两个不同的类加载器加载了该类两次。由于硬编码引用,您已经静态加载了类,并且在加载实现时加载了第二个副本。这不是作为答案发布的,因为虽然我可以告诉你为什么会出现错误,但没有足够的信息告诉你如何修复它(而且我的类加载器专业知识有些过时了)。
  • 是的。问题是我两次加载了类加载器,现在修复了它。谢谢。

标签: java reflection jar classloader


【解决方案1】:

由不同类加载器加载的相同类定义被 JVM 视为两个不同的类。

您的代码“URLClassLoader.newInstance”同时获取不同的类加载器

第一个(handler#parameter)是:URLClassLoader#1 & com.hello.Request

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

“com.hello.Request 无法转换为 com.hello.Request”。

实际错误是

“URLClassLoader#2 com.hello.Request 无法转换为 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);
}

【讨论】:

  • 非常感谢您的回答。现在修好了。
猜你喜欢
  • 1970-01-01
  • 2018-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
相关资源
最近更新 更多