【问题标题】:JavaClassLoader: Why an "NoSuchMethodEx" is thrown here?JavaClassLoader:为什么这里会抛出“NoSuchMethodEx”?
【发布时间】:2015-05-25 19:18:53
【问题描述】:

“JavaClassLoader”库有问题。我想为应用程序编写一个启动器。最后应该可以关闭程序,更新并重新启动。 现在,当我尝试使用参数调用方法时,我总是得到一个 NoSuchMethodEx。

我要启动的主类,实现如下(apache Daemon 的一部分):

package org.apache.commons.daemon;
public interface Daemon {
    public void init(DaemonContext context) throws DaemonInitException, Exception;
    public void start() throws Exception;
    public void stop() throws Exception;
    public void destroy();
}

在我的启动器中发生以下情况:

// set cglib proxy
ProxyProviderFactory.setDefaultProxyProvider(new CglibProxyProvider());
// load instance
JarClassLoader jcl = new JarClassLoader();
jcl.add("application.jar");
JclObjectFactory factory = JclObjectFactory.getInstance(true);
this.application = (Daemon) factory.create(jcl, "de.FabiUnne.Application");

现在,如果我尝试调用不带参数的方法(例如 #start()),一切正常。当我尝试调用 #init(DaemonContext) 方法时出现错误。

堆栈跟踪:

Exception in thread "main" java.lang.NoSuchMethodException: de.FabiUnne.Application.init(org.apache.commons.daemon.DaemonContext)
  at java.lang.Class.getMethod(Class.java:1670)
  at org.xeustechnologies.jcl.proxy.CglibProxyProvider$CglibProxyHandler.intercept(CglibProxyProvider.java:52)
  at org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init(<generated>)
  and 2 more...

有趣的是,无论如何,该方法确实存在。

<- this.application.getClass().getMethods()
-> [ ...
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init(org.apache.commons.daemon.DaemonContext) throws org.apache.commons.daemon.DaemonInitException,java.lang.Exception, 
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.start() throws java.lang.Exception, 
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.destroy(), 
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.stop() throws java.lang.Exception, 
... ]

为什么我还是不能调用#init() 方法?

【问题讨论】:

    标签: java reflection nosuchmethoderror cglib


    【解决方案1】:

    我不熟悉您使用的框架。但是,如果我做对了,那么您创建的新类加载器就是异常的原因。如果您从 jcl 中获取 DaemonContext 的实例,您应该能够调用该方法。您还可以创建新的类加载器作为应用程序类加载器的子级。目前的方式是,每个不同的类加载器都有两个不同类型的 DaemonContext 类。

    【讨论】:

    • 你认为用上下文类加载器jcl创建一个新线程可以加载正确的类DaemonContext吗?
    • 好的,我通读了 Jcl doku...据我所知,这实际上应该可以工作。请提供您用于实际调用 init(...) 的代码。
    【解决方案2】:

    jcl: manipulating-class-loading-order

    @ChristianFrommeyer 给了我解决方案。我想解释它,所以它是自己的答案。

    启动器仍由“普通”类加载器加载。在此类中加载的所有对象都将由与 Launcher 相同的类加载器加载。 我现在从 (github.com/kamranzafar/JCL) 的另一个 ClasLoader 加载。作为依赖项存储在应用程序中的类在第二个加载器上加载。这个类不一样,跟上面加载的一样。

    public final void org.apache.commons.daemon.Daemon.init( ... ), 
    

    不一样

    public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init( ... ), 
    

    所以我告诉 JCL,他不应该覆盖加载的对象。在这里,下面的Loader实现了同样的效果。

    jcl.getCurrentLoader().setOrder(1); // or
    jcl.getParentLoader().setOrder(1); // or
    jcl.getSystemLoader().setOrder(1);
    

    两个类加载器中存在的对象现在是相同的,因为它们都来自本地加载器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-24
      • 2021-06-18
      • 1970-01-01
      • 1970-01-01
      • 2019-12-03
      • 2018-01-05
      • 2013-12-05
      相关资源
      最近更新 更多