java - Java EE/Jakarta EE 是否支持 Java 模块系统?是否可以使用 Java 模块系统制作 Web 应用程序?

标签 java spring intellij-idea reflection java-11

我正在使用 Java 11 和 Maven 3.6.1 构建我的第一个模块化应用程序。我的 IDE 是 IntellijIDEA 2019.1.3。我添加了一个模块“应用程序”并添加了 module-info.java,但我很困惑,因为即使我向应用程序模块添加了 spring 依赖项并且我没有打开我的模块或模块中的一些包用于反射。

我在 IDE 的功能中添加了 module-info.java,它迫使我添加 requires 语句。到目前为止,一切都很好。但是为什么它可以在不打开模块进行反射的情况下工作呢?这是 Java 11 或我的 IDE 版本中的一些新功能吗?我做错了吗?

我的module-info.java:

module app {
    requires spring.web;
    requires spring.webmvc;
    requires javax.servlet.api;
    requires spring.context;
}

我试图在 SO 和 JetBrains 上找到答案,但我失败了。

我看到这个人 (https://youtu.be/hxsCYxZ1gXU?t=2238) 正在使用 spring 模块,他的 IDE 要求他打开模块进行反射。我下载了他的项目并删除了 opens 语句,它仍然在我的 IDE 中编译。

还有一个问题:如何使用 IDE 检查模块路径?我怎样才能看到有哪些模块以及我的类路径上有什么(现在应该什么都没有)?

编辑:我刚刚意识到我的 IDE 打印 命令行参数:--add-opens=java.base/java.lang=ALL-UNNAMEDlog。我想这就是原因,但我找不到这个 arg 来自哪里。我走对了吗?

第 2 条编辑: 在控制台日志中,命令行参数为:

--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
-Djava.util.logging.config.file=C:\Users\Nedim\.IntelliJIdea2019.2\system\tomcat\Unnamed_ems\conf\logging.properties
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djdk.module.showModuleResolution=true
-Dcom.sun.management.jmxremote=
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.password.file=C:\Users\Nedim\.IntelliJIdea2019.2\system\tomcat\Unnamed_ems\jmxremote.password
-Dcom.sun.management.jmxremote.access.file=C:\Users\Nedim\.IntelliJIdea2019.2\system\tomcat\Unnamed_ems\jmxremote.access
-Djava.rmi.server.hostname=127.0.0.1
-Djdk.tls.ephemeralDHKeySize=2048
-Djava.protocol.handler.pkgs=org.apache.catalina.webresources
-Dignore.endorsed.dirs=
-Dcatalina.base=C:\Users\Nedim\.IntelliJIdea2019.2\system\tomcat\Unnamed_ems
-Dcatalina.home=D:\tomcat\apache-tomcat-9.0.21
-Djava.io.tmpdir=D:\tomcat\apache-tomcat-9.0.21\temp

另外,从我的日志中(我不确定这是否相关):

D:\tomcat\apache-tomcat-9.0.21\bin\catalina.bat run
[2019-11-08 05:42:34,404] Artifact app:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE:   "C:\Users\Nedim\.IntelliJIdea2019.2\system\tomcat\Unnamed_ems"
Using CATALINA_HOME:   "D:\tomcat\apache-tomcat-9.0.21"
Using CATALINA_TMPDIR: "D:\tomcat\apache-tomcat-9.0.21\temp"
Using JRE_HOME:        "C:\Program Files\Java\jdk-11.0.5"
Using CLASSPATH:       "D:\tomcat\apache-tomcat-9.0.21\bin\bootstrap.jar;D:\tomcat\apache-tomcat-9.0.21\bin\tomcat-juli.jar"

--show-module-resolution 打印出来:

root java.sql jrt:/java.sql
root jdk.management.jfr jrt:/jdk.management.jfr
root java.rmi jrt:/java.rmi
root jdk.jdi jrt:/jdk.jdi
root java.transaction.xa jrt:/java.transaction.xa
root java.xml.crypto jrt:/java.xml.crypto
root java.logging jrt:/java.logging
root java.xml jrt:/java.xml
root jdk.xml.dom jrt:/jdk.xml.dom
root jdk.jfr jrt:/jdk.jfr
root java.datatransfer jrt:/java.datatransfer
root jdk.httpserver jrt:/jdk.httpserver
root jdk.net jrt:/jdk.net
root java.naming jrt:/java.naming
root java.desktop jrt:/java.desktop
root java.prefs jrt:/java.prefs
root java.net.http jrt:/java.net.http
root jdk.compiler jrt:/jdk.compiler
root java.security.sasl jrt:/java.security.sasl
root jdk.jconsole jrt:/jdk.jconsole
root jdk.attach jrt:/jdk.attach
root java.base jrt:/java.base
root jdk.javadoc jrt:/jdk.javadoc
root jdk.management.agent jrt:/jdk.management.agent
root jdk.jshell jrt:/jdk.jshell
root jdk.jsobject jrt:/jdk.jsobject
root java.sql.rowset jrt:/java.sql.rowset
root java.management jrt:/java.management
root jdk.sctp jrt:/jdk.sctp
root java.smartcardio jrt:/java.smartcardio
root jdk.unsupported jrt:/jdk.unsupported
root jdk.scripting.nashorn jrt:/jdk.scripting.nashorn
root java.instrument jrt:/java.instrument
root java.security.jgss jrt:/java.security.jgss
root jdk.management jrt:/jdk.management
root jdk.security.auth jrt:/jdk.security.auth
root java.compiler jrt:/java.compiler
root java.scripting jrt:/java.scripting
root jdk.dynalink jrt:/jdk.dynalink
root jdk.unsupported.desktop jrt:/jdk.unsupported.desktop
root jdk.accessibility jrt:/jdk.accessibility
root jdk.jartool jrt:/jdk.jartool
root java.management.rmi jrt:/java.management.rmi
root jdk.security.jgss jrt:/jdk.security.jgss
jdk.security.jgss requires java.security.sasl jrt:/java.security.sasl
jdk.security.jgss requires java.logging jrt:/java.logging
jdk.security.jgss requires java.security.jgss jrt:/java.security.jgss
java.management.rmi requires java.naming jrt:/java.naming
java.management.rmi requires java.rmi jrt:/java.rmi
java.management.rmi requires java.management jrt:/java.management
jdk.accessibility requires java.desktop jrt:/java.desktop
jdk.unsupported.desktop requires java.desktop jrt:/java.desktop
jdk.dynalink requires java.logging jrt:/java.logging
jdk.security.auth requires java.naming jrt:/java.naming
jdk.security.auth requires java.security.jgss jrt:/java.security.jgss
jdk.management requires java.management jrt:/java.management
java.security.jgss requires java.naming jrt:/java.naming
jdk.scripting.nashorn requires jdk.dynalink jrt:/jdk.dynalink
jdk.scripting.nashorn requires java.logging jrt:/java.logging
jdk.scripting.nashorn requires java.scripting jrt:/java.scripting
java.sql.rowset requires java.logging jrt:/java.logging
java.sql.rowset requires java.sql jrt:/java.sql
java.sql.rowset requires java.naming jrt:/java.naming
jdk.jsobject requires java.desktop jrt:/java.desktop
jdk.jshell requires jdk.compiler jrt:/jdk.compiler
jdk.jshell requires java.compiler jrt:/java.compiler
jdk.jshell requires java.logging jrt:/java.logging
jdk.jshell requires java.prefs jrt:/java.prefs
jdk.jshell requires jdk.internal.ed jrt:/jdk.internal.ed
jdk.jshell requires jdk.internal.le jrt:/jdk.internal.le
jdk.jshell requires jdk.internal.opt jrt:/jdk.internal.opt
jdk.jshell requires jdk.jdi jrt:/jdk.jdi
jdk.management.agent requires java.management jrt:/java.management
jdk.management.agent requires java.management.rmi jrt:/java.management.rmi
jdk.javadoc requires java.compiler jrt:/java.compiler
jdk.javadoc requires java.xml jrt:/java.xml
jdk.javadoc requires jdk.compiler jrt:/jdk.compiler
jdk.attach requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat
jdk.jconsole requires java.desktop jrt:/java.desktop
jdk.jconsole requires jdk.management.agent jrt:/jdk.management.agent
jdk.jconsole requires jdk.attach jrt:/jdk.attach
jdk.jconsole requires java.management.rmi jrt:/java.management.rmi
jdk.jconsole requires java.management jrt:/java.management
jdk.jconsole requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat
jdk.jconsole requires jdk.management jrt:/jdk.management
jdk.jconsole requires java.rmi jrt:/java.rmi
java.security.sasl requires java.logging jrt:/java.logging
jdk.compiler requires java.compiler jrt:/java.compiler
java.prefs requires java.xml jrt:/java.xml
java.desktop requires java.xml jrt:/java.xml
java.desktop requires java.prefs jrt:/java.prefs
java.desktop requires java.datatransfer jrt:/java.datatransfer
java.naming requires java.security.sasl jrt:/java.security.sasl
jdk.xml.dom requires java.xml jrt:/java.xml
java.xml.crypto requires java.xml jrt:/java.xml
java.xml.crypto requires java.logging jrt:/java.logging
jdk.jdi requires jdk.attach jrt:/jdk.attach
jdk.jdi requires jdk.jdwp.agent jrt:/jdk.jdwp.agent
java.rmi requires java.logging jrt:/java.logging
jdk.management.jfr requires jdk.jfr jrt:/jdk.jfr
jdk.management.jfr requires java.management jrt:/java.management
jdk.management.jfr requires jdk.management jrt:/jdk.management
java.sql requires java.logging jrt:/java.logging
java.sql requires java.transaction.xa jrt:/java.transaction.xa
java.sql requires java.xml jrt:/java.xml
jdk.dynalink binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn
java.naming binds jdk.naming.rmi jrt:/jdk.naming.rmi
java.naming binds jdk.naming.dns jrt:/jdk.naming.dns
java.management binds java.management.rmi jrt:/java.management.rmi
java.management binds jdk.management jrt:/jdk.management
java.management binds jdk.management.jfr jrt:/jdk.management.jfr
java.compiler binds jdk.compiler jrt:/jdk.compiler
java.compiler binds jdk.javadoc jrt:/jdk.javadoc
java.base binds jdk.zipfs jrt:/jdk.zipfs
java.base binds jdk.localedata jrt:/jdk.localedata
java.base binds jdk.security.jgss jrt:/jdk.security.jgss
java.base binds java.security.jgss jrt:/java.security.jgss
java.base binds jdk.crypto.cryptoki jrt:/jdk.crypto.cryptoki
java.base binds java.smartcardio jrt:/java.smartcardio
java.base binds jdk.crypto.mscapi jrt:/jdk.crypto.mscapi
java.base binds jdk.crypto.ec jrt:/jdk.crypto.ec
java.base binds java.security.sasl jrt:/java.security.sasl
java.base binds java.naming jrt:/java.naming
java.base binds java.xml.crypto jrt:/java.xml.crypto
java.base binds jdk.jdeps jrt:/jdk.jdeps
java.base binds jdk.javadoc jrt:/jdk.javadoc
java.base binds jdk.jlink jrt:/jdk.jlink
java.base binds jdk.jartool jrt:/jdk.jartool
java.base binds jdk.compiler jrt:/jdk.compiler
java.base binds java.desktop jrt:/java.desktop
java.base binds java.management jrt:/java.management
java.base binds jdk.security.auth jrt:/jdk.security.auth
java.base binds java.logging jrt:/java.logging
java.base binds jdk.charsets jrt:/jdk.charsets
jdk.jshell binds jdk.editpad jrt:/jdk.editpad
java.desktop binds jdk.accessibility jrt:/jdk.accessibility
java.desktop binds jdk.unsupported.desktop jrt:/jdk.unsupported.desktop
java.datatransfer binds java.desktop jrt:/java.desktop
java.scripting binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn
jdk.internal.jvmstat binds jdk.jstatd jrt:/jdk.jstatd
jdk.jstatd requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat
jdk.jstatd requires java.rmi jrt:/java.rmi
jdk.editpad requires java.desktop jrt:/java.desktop
jdk.editpad requires jdk.internal.ed jrt:/jdk.internal.ed
jdk.jlink requires jdk.jdeps jrt:/jdk.jdeps
jdk.jlink requires jdk.internal.opt jrt:/jdk.internal.opt
jdk.jdeps requires java.compiler jrt:/java.compiler
jdk.jdeps requires jdk.compiler jrt:/jdk.compiler
jdk.crypto.cryptoki requires jdk.crypto.ec jrt:/jdk.crypto.ec
jdk.naming.dns requires java.naming jrt:/java.naming
jdk.naming.rmi requires java.naming jrt:/java.naming
jdk.naming.rmi requires java.rmi jrt:/java.rmi

最佳答案

让我们总结一下问题和答案。

我重命名了我的问题以更好地适应问题,因此将来可以重复使用。当我开始这个线程问题是:我是否必须在 module-info.java 中添加一个 open 语句来打开模块进行反射。发生的事情是我使用 Java 11 和 Spring 制作了模块化 Web 应用程序,我注意到我的设置不需要打开模块或其中的任何包进行反射。

使用 --show-module-resolution 标志仅列出 JDK 模块。它没有显示我的任何模块。

用户@Holger 在这个问题上帮助最大。他建议使用 System.out.println("classpath: "+ System.getProperty("java.class.path")); 来查看类路径上的内容。并且没有任何相关的内容。

然后他建议在代码的某处使用System.out.println(SomeClass.class.getModule()); 看看我的代码是属于声明的模块还是未命名的模块。原来它属于未命名的模块。

所以结论是 Apache Tomcat 的 ClassLoader 将我的类以及 Spring jar 加载到未命名的模块中。

然后我问 Apache 支持如何让 Tomcat 正确加载我的模块,答案是:

You can't. The Servlet API (nor any part of Java EE / Jakarta EE) does not make use of the module system. Mark

但我还是放不下,因为我在 Youtube 上看到了一个叫 Jaap Coomans 的人。使用模块,他正在使用 Tomcat。他把他的联系方式放在最后一张幻灯片上,所以我决定问他发生了什么事。这是他回答的相关部分:

From what I get from your description the main difference between your setup and the one in my talk is that your are running a Spring web application on a separate Tomcat server, whereas in my talk I'm building a Spring Boot application with an embedded Tomcat server. This is a subtle difference that is likely to be the cause of the issue you're running into. With Spring Boot, the application itself is booted from the command line. The application then launches the embedded Tomcat, making the application module itself in charge of classloading and the classpath and modulepath. Most of this is managed under the hood by Spring Boot, so you could say Spring (Boot) is in charge of booting Tomcat. The approach you've taken is the "classic" Spring (without Boot) setup where Tomcat starts the process and is in charge of classloading and loads your application. To put it a little simpler: in the example of my talk Spring starts Tomcat, in your case it is the other way around.

(...)

It is true that currently the Java / Jakarta EE spec does not support the module system. Due to the nature of the spec I guess this may actually be quite of a challenge to overcome. I'm not sure where this topic is on the roadmap of Jakarta EE right after the transition to the Eclipse foundation. That's something I will definitely look out for. Unfortunately the answer to your actual question is still that it is not possible in your setup.

这里的关键要点是:

  • 核心 Java 支持 Java 模块系统。
  • Java EE/Jakarta EE 不使用 Java 模块系统,因此 Web 容器会将所有类放到一个未命名的模块中。单独的 Tomcat 设置会发生这种情况。
  • 正如 Jaap 所说,Spring Boot 使用嵌入式 Tomcat,使应用程序模块本身负责类加载以及类路径和模块路径。

最后,在我得到 @Holger 和 Jaap 的答复后,我找到了 this和一个有趣的可能solution .我没试过。

这是一条漫长的道路,但我们最终明确了。

关于java - Java EE/Jakarta EE 是否支持 Java 模块系统?是否可以使用 Java 模块系统制作 Web 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58737469/

相关文章:

swing - 我正在用 Java 制作游戏,每当我尝试调出游戏菜单时,程序就会最小化?

java - Whitelabel错误页面部署到服务器后出现错误

java - 如何在 Spring 中解析 XML 消息负载?

java - Spring 休息 : when pathVariable matches multiple entities should spring return a list or throw error

java - 为什么与 `==` 运算符相比,整数对象没有拆箱?

java - 解决 Java Spring 应用程序中的竞争条件的最佳方法是什么?

intellij-idea - 如何使用其他插件的扩展点? (Intellij 想法)

Ubuntu 16.04 IntelliJ 启动器在重启后消失

java - 想法tomcat8部署总是404

java - 显示 : exception is never thrown in body of try statement 的语法警告