Поддерживает ли Java EE / Jakarta EE систему модулей Java? Можно ли сделать веб-приложение с модульной системой Java? - PullRequest
1 голос
/ 06 ноября 2019

Я создаю свое первое модульное приложение с Java 11 и Maven 3.6.1. Моя IDE - IntellijIDEA 2019.1.3. Я добавил модуль 'приложение' и добавил module-info.java, но я запутался, потому что мое приложение работает, даже если я добавил пружинные зависимости в модуль приложения, и я не открыл свой модуль или какой-либо пакет в модуле для отражения.

Я добавил module-info.java с помощью функции IDE, и это заставляет меня добавлять 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), работающего с пружинными модулями, и его IDE требует, чтобы он открыл модуль для размышлений. И я скачал его проект и удалил операторы opens, и он все еще компилируется в моей IDE.

И еще один вопрос: Как я могу проверить путь к модулю с помощью моей IDE? Как я могу увидеть, какие модули есть и что находится на моем пути к классам (сейчас ничего не должно быть)?

РЕДАКТИРОВАТЬ: Iтолько что понял, что моя IDE печатает журнал Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED. Я полагаю, что это причина, но я не могу найти, откуда исходит этот аргумент. Я на правильном пути?

РЕДАКТИРОВАТЬ № 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

Ответы [ 2 ]

1 голос
/ 13 ноября 2019

Позвольте обобщить проблему и ответ.

Я переименовал свой вопрос, чтобы лучше подходить к проблеме, поэтому в будущем его можно будет использовать повторно. Когда я начинал эту тему, я задавал вопрос: нужно ли добавлять открытый оператор в module-info.java, чтобы открыть модуль для размышлений. Случилось так, что я создал модульное веб-приложение с Java 11 и Spring и заметил, что для моей установки не требуются открытые модули или какие-либо пакеты в них для отражения.

При использовании флага --show-module-resolution перечислены только модули JDK. Он не показывал ни один из моих модулей.

Пользователь @Holger больше всего помог с этой проблемой. Он рекомендовал использовать System.out.println("classpath: " + System.getProperty("java.class.path"));, чтобы увидеть, что находится на пути к классам. И не было ничего релевантного.

Затем он предложил использовать где-нибудь в коде System.out.println(SomeClass.class.getModule());, чтобы увидеть, принадлежит ли мой код объявленному модулю или неназванному модулю. И оказалось, что он принадлежит безымянному модулю.

Таким образом, был сделан вывод, что ClassLoader Apache Tomcat загружает мои классы, а также jar-файлы Spring в безымянный модуль.

Затем я попросил поддержки Apache. Как я могу заставить Tomcat правильно загрузить мои модули и получить ответ:

Вы не можете. Servlet API (ни какая-либо часть Java EE / Jakarta EE) не использует модульную систему. Марк

Но я все еще не мог отпустить, потому что я видел парня по имени Яап Куманс на [Youtube] (https://www.youtube.com/watch?v=u4VV9NSK_0Y), работающего с модулями, и ониспользовал Tomcat. Он поместил свой контакт на одном из последних слайдов, поэтому я решил спросить его, что происходит. И вот соответствующая часть его ответа:

Из того, что я понял из вашего описания, основное различие между вашими настройками и тем, что в моем выступлении, заключается в том, что вы запускаете веб-приложение Spring на отдельном сервере Tomcat, тогда как в моем выступлении я создаю приложение Spring Boot со встроеннымСервер Tomcat. Это тонкое различие, которое, вероятно, является причиной проблемы, с которой вы столкнулись. С помощью Spring Boot само приложение загружается из командной строки. Затем приложение запускает встроенный Tomcat, делая модуль приложенияСам отвечает за загрузку классов, classpath и modulepath. Большая часть этого управляется Spring Boot, так что вы можетескажем, Spring (Boot) отвечает за загрузку Tomcat. Подход, который вы выбрали, - это «классическая» настройка Spring (без загрузки), когда Tomcat запускает процесс и отвечает за загрузку классов и загрузку вашего приложения. Проще говоря: в примере моего выступления Spring запускает Tomcat, в вашем случае все наоборот.

(...)

Это правда, что в настоящее время спецификация Java / Jakarta EE не поддерживает систему модулей. Я полагаю, что из-за специфики спецификации это может быть довольно сложной задачей. Я не уверен, где эта тема находится на дорожной карте Джакарты EE сразу после перехода к фундаменту Eclipse. Это то, что я обязательно позабочусь. К сожалению, ответ на ваш актуальный вопрос по-прежнему заключается в том, что это невозможно в вашей настройке.

Ниже приведены ключевые выводы:

  • ЯдроJava поддерживает систему модулей Java.
  • Java EE / Jakarta EE не использует систему модулей Java, поэтому веб-контейнер помещает все классы в неназванный модуль. Это происходит с отдельной установкой Tomcat.
  • Как заявил Jaap, Spring Boot использует встроенный Tomcat, в результате чего сам модуль приложения отвечает за загрузку классов, а также путь к классам и путь к модулям.

И, наконец, после того, как я получил ответ от @Holger и Jaap, я нашел это и одно интересное возможное решение . Я не пробовал.

Это был долгий путь, но мы дали понять, в конце концов.

1 голос
/ 07 ноября 2019

Да. Вы должны явно разрешить отражение с помощью директивы opens.

Вы можете предоставить пакет для отражения конкретному модулю, используя 'opens to'

module org.util.web.server {

    exports org.util.web.server;
    opens org.util.web.server to org.jetbrains.annotations;
}

или Вы можете открыть пакет для отражения всеммодули, использующие

module org.util.web.server {

    exports org.util.web.server;
    opens org.util.web.server;
}
...