【问题标题】:Tomcat Catalina context - add existing servlet to contextTomcat Catalina 上下文 - 将现有 servlet 添加到上下文
【发布时间】:2021-07-19 00:33:50
【问题描述】:

我想将现有的 servlet 添加到上下文中,当我使用 (Main.java) 时它可以工作:

Tomcat.addServlet(ctx, "MyServlet", new MyServlet());
ctx.addServletMappingDecoded("/url_pattern", "MyServlet")

但是,我在 servlet 中有注解来映射 url_pattern(MyServlet.java):

@WebServlet(name = "MyServlet", urlPatterns = { "/url_pattern" })
@MultipartConfig(
  fileSizeThreshold = 1024 * 1024 * 1, // 1 MB
  maxFileSize = 1024 * 1024 * 10,      // 10 MB
  maxRequestSize = 1024 * 1024 * 100   // 100 MB
)

很遗憾,这些注释不起作用。我想从 Main.java 中删除映射并使用我的 Servlet 注释中的映射。

我使用的是 Tomcat 10.0.0。

Main.java

import java.io.File;

import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

public class Main {

    public static void main(String[] args) throws LifecycleException,
    InterruptedException {
    Tomcat tomcat = new Tomcat();
    tomcat.setPort(8082);

    Context ctx = tomcat.addContext("", new File(".").getAbsolutePath());

    Tomcat.addServlet(ctx, "MyServlet", new MyServlet());
    
    ctx.setAllowCasualMultipartParsing(true);
    ctx.addServletMappingDecoded("/url_pattern", "MyServlet");
    
    
    tomcat.start();
    tomcat.getConnector();
    }
}

【问题讨论】:

  • 您使用 Servlet 5.0 类和注释 (jakarta.*) 还是 Servlet 4.0 类 (javax.*)? Tomcat 10 是一个 Servlet 5.0 容器。
  • 我使用 jakarta.servlet 5.0 和 jakarta.annotaion 2.0(据我所知,这是最新版本)。 Tomcat 也没有在 web.xml 中看到 Servlet 映射。
  • 我还想补充一点,当我从 Eclipse 运行 tomcat 服务器时,这些注释有效,但是当我使用 Main 类(嵌入式 tomcat)时,这些注释不起作用。
  • 您可以将Main 课程的内容添加到您的问题中吗?是否调用了Tomcat.addWebapp 方法,该方法执行通常的上下文初始化和注释扫描?
  • 我已经用主课内容编辑了我的问题。我不调用Tomcat.addWebapp,我会再看一遍文档并检查addWebapp方法。

标签: java tomcat servlets annotations catalina


【解决方案1】:

嵌入式 Tomcat 背后的想法是在代码中完成,通常 Tomcat 通过配置完成。因此通过注解配置servlet并不像在Tomcat中那样简单。

你将面临两个问题:

注解扫描

Tomcat#addContext 和 Tomcat#addWebapp 之间的主要区别在于后者添加了一些默认的 web.xml(jsp 和 default servlet)并扫描 Servlet 3.0 注释和 ServletContainerInitializers。

如果您不需要或不想要默认的web.xml 配置,您可以通过以下方式获得相同的东西:

Context ctx = tomcat.addContext("", new File(".").getAbsolutePath());
ctx.addLifecycleListener(new ContextConfig());

资源

即使在启用注释扫描之后,Tomcat 也不会找到您的 servlet,因为它会在您的 docBase(您设置为当前文件夹)的 /WEB-INF/classes 下查找。这可能是一个空文件夹。如果您希望 Tomcat 也扫描应用程序中的类,您需要:

  1. 找到包含Main 类的 JAR 文件或目录,
  2. 将该 JAR 的内容装载到应用程序的 /WEB-INF/classes(虚拟)文件夹(参见 Tomcat resources):
public static void main(String[] args) throws LifecycleException, InterruptedException {
   ...
   // Add the JAR/folder containing this class to PreResources
   final WebResourceRoot root = new StandardRoot(ctx);
   final URL url = findClassLocation(Main.class);
   root.createWebResourceSet(ResourceSetType.PRE, "/WEB-INF/classes", url, "/");
   ctx.setResources(root);
   ...
}

/*
 * Tries to find the URL of the JAR or directory containing {@code clazz}.
 */
private static URL findClassLocation(Class< ? > clazz) {
    return clazz.getProtectionDomain().getCodeSource().getLocation();
}

总结

最后你会得到:

    public static void main(String[] args) throws LifecycleException {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8082);
        final Context ctx = tomcat.addContext("", Paths.get(".").toAbsolutePath().toString());
        // Add the standard ContextConfig, which scans for annotations
        ctx.addLifecycleListener(new ContextConfig());
        // Add the JAR/folder containing this class to PreResources
        final WebResourceRoot root = new StandardRoot(ctx);
        final URL url = findClassLocation(Main.class);
        root.createWebResourceSet(ResourceSetType.PRE, "/WEB-INF/classes", url, "/");
        ctx.setResources(root);
        // Run Tomcat
        tomcat.getConnector();
        tomcat.start();
        tomcat.getServer().await();
    }

【讨论】:

  • 没错,有时再读一遍文档是个好主意!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 2010-12-10
  • 2010-09-08
  • 2015-08-10
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多