JavaClassLoader:为什么" NoSuchMethodEx"扔在这里?

时间:2015-05-25 19:18:54

标签: java reflection nosuchmethoderror cglib

我遇到了" JavaClassLoader"图书馆。我想为应用程序编写一个启动程序。最后应该可以关闭程序,更新并重新开始。 现在,当我尝试使用参数调用方法时,我总是得到一个NoSuchMethodEx。

我想要启动的主类,实现如下(apache守护进程的一部分):

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)方法时出现错误。

stacktrace:

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()方法呢?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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);

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