Проблемы загрузчика классов в Jetty Embbeded WebApp Deployments - PullRequest
0 голосов
/ 27 апреля 2018

После другой вопрос , если вы добавляете объект к атрибутам контекста, который был установлен во время метода main (загрузчик классов системы), но затем использовался в контексте загрузчика классов Web-приложения (т. Е. В сервлет), есть проблемы, которые я не могу решить:

Происходит одно из двух:

  1. без дополнительных изменений, вы получаете ClassCastException при попытке получить объект из атрибутов контекста сервлета, или,
  2. Добавляя WebAppContext.addSystemClasses(server, SomeClass.class.getName()), вы получаете java.lang.LinkageError: loader constraint violation: when resolving method... вместо. Это скорее всего потому, что я включил только базу

Если не считать принудительного использования SystemClassLoader в WebApp, есть ли способ обойти это? Это жизнеспособное решение, и каковы недостатки этого?

1 Ответ

0 голосов
/ 28 апреля 2018

Не пытайтесь разрешить класс во время выполнения. Это означает, что если вы просто используете класс, в минуту, когда он загружен, он зафиксирован в том, что является текущим контекстным загрузчиком классов. Будьте внимательны к этому. А еще лучше, используйте строки или пакеты, всегда здесь.

Использование класса в привязке напрямую связывает класс с неправильным системным загрузчиком классов.

Пример из 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, это также обеспечит нормальную работу вашего 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();
            }
        }
    }
}
...