У меня была аналогичная ситуация, но мне нужно было предоставить один сингл с сервлетом, развернутым через войну, с помощью горячего (повторного) развертывания в контейнере Jetty. Принятый ответ был не совсем тем, что мне нужно в моем случае, так как сервлет имеет жизненный цикл и контекст, управляемые установщиком.
Я закончил с применением грубой силы, добавив объект в server
, который сохраняется для жизни контейнера, а затем извлекает объект из сервлета (ов). Это потребовало загрузки класса объекта в родительский (системный) загрузчик классов, чтобы war Webapp не загружал свою собственную версию класса в свой собственный загрузчик классов, что вызвало бы исключение литья, как описано здесь здесь .
Код сервера Embedded Jetty:
Server server = new Server(8090);
// Add all classes related to the object(s) you want to share here.
WebAppContext.addSystemClasses(server, "my.package.MyFineClass", ...);
// Handler config
ContextHandlerCollection contexts = new ContextHandlerCollection();
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] { contexts });
server.setHandler(handlers);
// Deployer config (hot deploy)
DeploymentManager deployer = new DeploymentManager();
DebugListener debug = new DebugListener(System.err,true,true,true);
server.addBean(debug);
deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
deployer.setContexts(contexts);
deployer.setContextAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
WebAppProvider webapp_provider = new WebAppProvider();
webapp_provider.setMonitoredDirName("/.../webapps");
webapp_provider.setScanInterval(1);
webapp_provider.setExtractWars(true);
webapp_provider.setConfigurationManager(new PropertiesConfigurationManager());
deployer.addAppProvider(webapp_provider);
server.addBean(deployer);
// Other config...
// Tuck any objects/data you want into the root server object.
server.setAttribute("my.package.MyFineClass", myFineSingleton);
server.start();
server.join();
Пример сервлета:
public class MyFineServlet extends HttpServlet
{
MyFineClass myFineSingleton;
@Override
public void init() throws ServletException
{
// Sneak access to the root server object (non-portable).
// Not possible to cast this to `Server` because of classloader restrictions in Jetty.
Object server = request.getAttribute("org.eclipse.jetty.server.Server");
// Because we cannot cast to `Server`, use reflection to access the object we tucked away there.
try {
myFineSingleton = (MyFineClass) server.getClass().getMethod("getAttribute", String.class).invoke(server, "my.package.MyFineClass");
} catch (Exception ex) {
throw new ServletException("Unable to reflect MyFineClass instance via Jetty Server", ex);
}
}
@Override
protected void doGet( HttpServletRequest request,
HttpServletResponse response ) throws ServletException, IOException
{
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("Hello from MyFineServlet
");
response.getWriter().println("Here's: " + myFineSingleton.toString());
}
}
Мой файл сборки для сервлета (sbt) помещал my.package.MyFineClass
в «предоставленный» объем, чтобы он не попал в войну, поскольку он уже будет загружен на сервер Jetty.