Tomcat Catalina 上下文 - 将现有 servlet 添加到上下文 注释扫描资源总结

问题描述

我想将现有的 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,new MyServlet());
    
    ctx.setAllowCasualMultipartParsing(true);
    ctx.addServletMappingDecoded("/url_pattern","MyServlet");
    
    
    tomcat.start();
    tomcat.getConnector();
    }
}

解决方法

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

您将面临两个问题:

注释扫描

Tomcat#addContextTomcat#addWebapp 的主要区别在于后者添加了一些默认的 web.xmljspdefault servlet)并扫描 Servlet 3.0注释和 ServletContainerInitializer

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

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

资源

即使启用注释扫描,Tomcat 也不会找到您的 servlet,因为它会在您的 /WEB-INF/classes(您设置为当前文件夹)的 docBase 下查找。这可能是一个空文件夹。如果您希望 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) {
    final ClassLoader cl = Main.class.getClassLoader();
    if (cl instanceof URLClassLoader) {
        final URLClassLoader urlCl = (URLClassLoader) cl;
        final String mainClassName = clazz.getName().replaceAll("\\.","/") + ".class";
        final String mainResource = urlCl.findResource(mainClassName)//
                                         .toString();
        for (final URL url : urlCl.getURLs()) {
            if (mainResource.toString().startsWith(url.toString())) {
                return url;
            }
        }
    }
    throw new RuntimeException("Didn't find the URL of the Main class.");
}

总结

最后你会得到:

    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,"/");
        ctx.setResources(root);
        // Run Tomcat
        tomcat.getConnector();
        tomcat.start();
        tomcat.getServer().await();
    }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...