Я пытаюсь создать встроенный сервер Tomcat jpms.
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>compile</scope>
</dependency>
<!-- Tomcat -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>10.1.24</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>10.1.24</version>
</dependency>
</dependencies>
и это модуль-info.java:
module my_custom_module {
requires org.slf4j;
requires jakarta.servlet;
requires org.apache.tomcat.jasper;
requires org.apache.tomcat.catalina;
}
проект компилируется и запускается без проблем:
java --module-path target/lib/ -m my_custom_module/a.b.c.module.tomcat.MainClass
это мой код:
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Stream;
public class HttpContainer {
public static final HttpContainer instance = new HttpContainer();
private static final Logger logger = LoggerFactory.getLogger(HttpContainer.class);
private static final String contextPath = "/api";
private static final String host = System.getenv("HTTP_SERVER_HOST");
private static final String port = System.getenv("HTTP_SERVER_PORT");
private static final String appBase = "/tmp/tomcat";
private static Tomcat tomcat;
private HttpContainer() {
createAppBaseDirectory();
TomcatURLStreamHandlerFactory.disable();
tomcat = new Tomcat();
tomcat.setHostname(Optional.ofNullable(host).orElse("0.0.0.0"));
tomcat.setPort(Integer.parseInt(Optional.ofNullable(port).orElse("8080")));
tomcat.setBaseDir(appBase);
Context context = tomcat.addWebapp(contextPath, appBase);
tomcat.addServlet(contextPath, "hello", new HelloServlet());
context.addServletMappingDecoded("/hello", "hello");
}
public void start() {
try {
tomcat.getConnector();
tomcat.start();
logger.info("Tomcat server started");
tomcat.getServer().await();
} catch (Exception e) {
logger.error("Tomcat error", e);
}
}
public void stop() {
try (Stream<Path> pathStream = Files.walk(Path.of(appBase))) {
pathStream.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(java.io.File::delete);
tomcat.stop();
logger.info("Tomcat server stopped");
} catch (Exception e) {
logger.error("Tomcat error", e);
}
}
private void createAppBaseDirectory() {
try {
Path appBasePath = Path.of(appBase);
if (!Files.exists(appBasePath)) {
Files.createDirectory(appBasePath);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
моя проблема:
когда я отправляю http-запрос, сервер выдает эту ошибку:
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
May 24, 2024 1:59:21 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
May 24, 2024 1:59:21 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
May 24, 2024 1:59:21 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/10.1.24]
May 24, 2024 1:59:21 PM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
INFO: No global web.xml found
May 24, 2024 1:59:22 PM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs
were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
May 24, 2024 1:59:22 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
May 24, 2024 1:59:24 PM org.apache.catalina.core.StandardHostValve invoke
SEVERE: Exception Processing [/api/hello]
java.lang.IllegalAccessError: class jakarta.security.auth.message.config.AuthConfigFactory (in module jakarta.security.auth.message) cannot access class org.apac
he.catalina.authenticator.jaspic.AuthConfigFactoryImpl (in module org.apache.tomcat.catalina) because module jakarta.security.auth.message does not read module o
rg.apache.tomcat.catalina
at [email protected]/jakarta.security.auth.message.config.AuthConfigFactory.lambda$getFactory$0(AuthConfigFactory.java:82)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
at [email protected]/jakarta.security.auth.message.config.AuthConfigFactory.getFactory(AuthConfigFactory.java:76)
at [email protected]/org.apache.catalina.authenticator.AuthenticatorBase.findJaspicProvider(AuthenticatorBase.java:1268)
at [email protected]/org.apache.catalina.authenticator.AuthenticatorBase.getJaspicProvider(AuthenticatorBase.java:1261)
at [email protected]/org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:473)
at [email protected]/org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at [email protected]/org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at [email protected]/org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at [email protected]/org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at [email protected]/org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
at [email protected]/org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at [email protected]/org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at [email protected]/org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at [email protected]/org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at [email protected]/org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at [email protected]/org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at [email protected]/org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:1583)
как исправить эту проблему?
ой, извините, я имею в виду встроенный сервер Tomcat. Вопрос обновлен
Что-то не так с ботом SO, слишком много отрицательных голосов по реальным проблемам, а голоса требуют более подробной информации. При этом не спрашивая в комментариях и не оставляя предложений для ОП.




В качестве временного решения вы можете добавить аргумент виртуальной машины в свои конфигурации, как указано в сообщении об исключении:
java.lang.IllegalAccessError: class jakarta.security.auth.message.config.AuthConfigFactory (in module jakarta.security.auth.message)
cannot access class org.apache.catalina.authenticator.jaspic.AuthConfigFactoryImpl (in module org.apache.tomcat.catalina)
because module jakarta.security.auth.message does not read module org.apache.tomcat.catalina
Это будет означать что-то вроде промежуточного решения:
--add-reads jakarta.security.auth.message=org.apache.tomcat.catalina
Хотя в идеале такой доступ не должен требоваться, а аргументы предназначены для целей совместимости.
это решение работает, спасибо, но есть ли какое-нибудь решение сделать это программно? я не могу использовать это решение в своем проекте!
@ mah454 Не совсем уверен в процессе сборки tomcat, но в основном объявления их модулей должны обеспечивать как requires jakarta.security.auth.message, так и provides jakarta.security.auth.message.config.AuthConfigFactory with org.apache.catalina.authenticator.jaspic.AuthConfigFactoryImpl. Таким образом, это будет означать изменение в tomcat указанного объявления модуля.
Зафиксированный ! простая проблема: Благодаря этому вопросу
только заменить:
Context context = tomcat.addWebapp(contextPath, appBase);
к
Context context = tomcat.addContext(contextPath, baseDir);
Что такое «автономный сервер JPMS Tomcat»?