Jetty Embbeded WebApp部署中的类加载器问题

时间:2018-04-27 20:44:59

标签: embedded-jetty jetty-9

another question开始,如果将对象添加到在main方法(系统类加载器)期间实例化的上下文属性,但随后在Web App类加载器上下文中使用(即,在servlet中) ,有些问题似乎无法解决:

发生以下两件事之一:

  1. 没有额外的更改,在尝试从servlet上下文的属性中获取对象时会出现ClassCastException,或者,
  2. 通过添加WebAppContext.addSystemClasses(server, SomeClass.class.getName()),您可以获得java.lang.LinkageError: loader constraint violation: when resolving method...。这可能是因为我只包括了基础
  3. 如果没有强制在WebApp中使用SystemClassLoader,那还有办法吗?这是一个可行的解决方案吗?这样做的缺点是什么?

1 个答案:

答案 0 :(得分:0)

不要尝试在运行时解析该类。 意思是,如果您只使用Class,它加载的分钟,它固定在当前上下文类加载器的任何位置。请注意这一点。 更好的是,总是在这里使用字符串或包。

使用Binding中的Class直接将Class绑定在错误的System Classloader上。

来自jetty-webapp-logging的示例(捕获服务器级别的所有日志记录)。

public class CentralizedWebAppLoggingBinding implements AppLifeCycle.Binding
{
    public String[] getBindingTargets()
    {
        return new String[]
        { "deploying" };
    }

    public void processBinding(Node node, App app) throws Exception
    {
        ContextHandler handler = app.getContextHandler();
        if (handler == null)
        {
            throw new NullPointerException("No Handler created for App: " + app);
        }

        if (handler instanceof WebAppContext)
        {
            WebAppContext webapp = (WebAppContext)handler;
            // Older API
            webapp.addSystemClass("org.apache.log4j.");
            webapp.addSystemClass("org.slf4j.");
            webapp.addSystemClass("org.apache.commons.logging.");
        }
    }
}

您也可以从WebApp的角度访问Class,这样可以确保您的ClasspathPattern也是理智的。

package jetty.deploy;

import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppLifeCycle;
import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.thread.ThreadClassLoaderScope;
import org.eclipse.jetty.webapp.ClasspathPattern;
import org.eclipse.jetty.webapp.WebAppContext;

public class ExampleClassLoaderBinding implements AppLifeCycle.Binding
{
    @Override
    public String[] getBindingTargets()
    {
        return new String[]{AppLifeCycle.DEPLOYING};
    }

    @Override
    public void processBinding(Node node, App app) throws Exception
    {
        ContextHandler handler = app.getContextHandler();
        if (handler == null)
        {
            throw new NullPointerException("No Handler created for App: " + app);
        }

        if (handler instanceof WebAppContext)
        {
            WebAppContext webapp = (WebAppContext) handler;
            try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(webapp.getClassLoader()))
            {
                // Demonstration of newer API
                ClasspathPattern systemClasspathPattern = webapp.getSystemClasspathPattern();
                systemClasspathPattern.add("org.apache.log4j.");
                systemClasspathPattern.add("org.slf4j.");
                systemClasspathPattern.add("org.apache.commons.logging.");

                // Example of accessing class via WebApp scope
               Class<?> clazz = Class.forName("com.corp.MyClass", true, scope.getScopedClassLoader());
               Object obj = clazz.getDeclaredConstructor().newInstance();
            }
        }
    }
}