问题描述
我想将现有的 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#addContext
和 Tomcat#addWebapp
的主要区别在于后者添加了一些默认的 web.xml
(jsp
和 default
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 也扫描您应用程序中的类,您需要:
- 找到包含您的
Main
类的 JAR 文件或目录, - 将该 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();
}