![](/img/trans.png)
[英]Gradle add nested subproject from a multi-module project as dependency of another subproject
[英]Using a spring-beans .xml file (in 'resources' folder) from a shared module with gradle multi module (subproject)
(為了幫助解決這個問題,我在這個問題的底部有 github 個鏈接)
我有(並且“從”以下 gradle 多個模塊/項目開始)
設置.gradle
rootProject.name = 'com.mycompany.myteam.myapp-rootProjectName'
include ':source:java:myapproot:myapp-toplayer-console-di-xml-one'
include ':source:java:myapproot:myapp-business-logic'
(maybe even a few that are purely .java/.class "code logic" libraries)
在子項目中:
':來源:java:myapproot:myapp-toplayer-console-di-xml-one'
我有典型的 Spring-Boot 啟動和使用 applicationContext.xml 的 spring-bean 設置。
./source/java/myapproot/myapp-toplayer-console-di-xml-one/src/main/java/demo/SpringBootApplicationContextXmlConsoleApplication.java
--
./source/java/myapproot/myapp-toplayer-console-di-xml-one/src/main/resources/applicationContext.xml
./source/java/myapproot/myapp-toplayer-console-di-xml-one/src/main/resources/orch.one.di.xml
./source/java/myapproot/myapp-toplayer-console-di-xml-one/src/main/resources/clientporxy.one.di.xml
“applicationContext.xml”的內容如下。 請注意,它有一個指向其他一些 .xml 文件的“指針”“導入”條目。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="orch.one.di.xml"/>
<import resource="clientproxy.one.di.xml"/>
</beans>
上面的一切都很好。 多年來,我一直在為許多不同的項目采用上述方法。
================================================ ==========
我想要做的是將 2 個“額外”*.di.xml 文件放入另一個gradle 模塊中。
設置.gradle
rootProject.name = 'com.mycompany.myteam.myapp-rootProjectName'
include ':source:java:myapproot:myapp-toplayer-console-di-xml-one'
include ':source:java:myapproot:myapp-business-logic'
(new one below)
include ':source:java:myapproot:myapp-shared-resxex'
我想將 *.di.xml 文件移動到這個不同的/新的 gradle-subproject/module。 (':source:java:myapproot:myapp-shared-resxex'要清楚)
所以現在我已經移動了兩個 *.di.xml 文件。
文件位置在這里:(在“資源”下)
./source/java/myapproot/myapp-shared-resxex/src/main/resources/orch.one.di.xml
./source/java/myapproot/myapp-shared-resxex/src/main/resources/clientproxy.one.di.xml
所以現在當我啟動“主”應用程序時,出現如下錯誤(我有點預料到這些錯誤)
Caused by: java.io.FileNotFoundException:
./source/java/myapproot/myapp-toplayer-console-di-xml-one/build/resources/main/clientproxy.one.di.xml
(No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
at java.base/sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:86)
at java.base/sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:184)
at org.springframework.core.io.UrlResource.getInputStream(UrlResource.java:187)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333)
我已經“嘗試”(並完成)了這樣的事情:
https://docs.gradle.org/current/userguide/cross_project_publications.html
就像很多天和很多小時都在試圖找出神奇的醬汁一樣。
所以,我的“一般”問題是
如何讓 spring bean.xml 文件從不同的 gradle-subproject/module 工作?
我將展示我的最新嘗試:
./source/java/myapproot/myapp-shared-resxex/build.gradle
configurations {
myCoolConfigurationName
}
task tryToPackageStuffForOtherSubprojectsTask(type: Jar) {
archiveClassifier
from sourceSets.main.resources
}
artifacts {
myCoolConfigurationName tryToPackageStuffForOtherSubprojectsTask
}
dependencies {
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-domain')
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-interfaces')
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-concrete')
}
進而:
./source/java/myapproot/myapp-toplayer-console-di-xml-one/build.gradle
plugins {
id "application"
}
apply plugin : "java"
ext {
javaMainClass = "demo.SpringBootApplicationContextXmlConsoleApplication"
}
application {
mainClassName = javaMainClass
}
task myCustomPrintClasspathTask {
doLast {
configurations.runtimeClasspath.each { println 'helloThere->' + it }
}
}
dependencies {
//the below line, if left not-commented-out, will produce a warning : "Execution optimizations have been disabled for task"
implementation project(path: ':source:java:myapproot:myapp-shared-resxex', configuration: 'myCoolConfigurationName')
implementation(group: 'org.springframework.boot', name: 'spring-boot-starter', version: springBootVersion) {
exclude module: "logback-classic"
}
implementation(group: 'org.springframework.boot', name: 'spring-boot-autoconfigure', version: springBootVersion) {
exclude module: "logback-classic"
}
implementation project(":source:java:myapproot:myapp-shared-resxex")
implementation project(':source:java:myapproot:myapp-business-logic')
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-domain')
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-interfaces')
implementation project(':source:java:myapproot:clientproxies:myclientproxy-root:myclientproxy-concrete')
implementation group: 'org.apache.commons', name: 'commons-lang3', version: commonsLangVersion
implementation group: 'javax.inject', name: 'javax.inject', version: "${javaxInjectVersion}"
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
implementation group: 'org.slf4j', name: 'slf4j-simple', version: slf4jSimpleVersion
testImplementation group: 'junit', name: 'junit', version: junitVersion
testImplementation group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
}
當我運行(一個干凈的構建然后)自定義任務時:
$ ./gradlew clean build
$ ./gradlew myCustomPrintClasspathTask
我得到以下 output:
> Task :source:java:myapproot:myapp-toplayer-console-di-xml-one:myCustomPrintClasspathTask
helloThere->./source/java/myapproot/myapp-shared-resxex/build/libs/myapp-shared-resxex.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter/2.7.5/c28e1546461803490588085345ba5d2897d232bc/spring-boot-starter-2.7.5.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/2.7.5/96646e63a2296d0a3209383e81cdb8c87ab2f913/spring-boot-autoconfigure-2.7.5.jar
helloThere->./source/java/myapproot/myapp-business-logic/build/libs/myapp-business-logic.jar
helloThere->./source/java/myapproot/clientproxies/myclientproxy-root/myclientproxy-concrete/build/libs/myclientproxy-concrete.jar
helloThere->./source/java/myapproot/clientproxies/myclientproxy-root/myclientproxy-interfaces/build/libs/myclientproxy-interfaces.jar
helloThere->./source/java/myapproot/clientproxies/myclientproxy-root/myclientproxy-domain/build/libs/myclientproxy-domain.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.12.0/c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e/commons-lang3-3.12.0.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.36/a41f9cfe6faafb2eb83a1c7dd2d0dfd844e2a936/slf4j-simple-1.7.36.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-logging/2.7.5/61f4c53e35baa31a269bbeb7bb9d5e781448feef/spring-boot-starter-logging-2.7.5.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-to-slf4j/2.17.2/17dd0fae2747d9a28c67bc9534108823d2376b46/log4j-to-slf4j-2.17.2.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.slf4j/jul-to-slf4j/1.7.36/ed46d81cef9c412a88caef405b58f93a678ff2ca/jul-to-slf4j-1.7.36.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.36/6c62681a2f655b49963a5983b8b0950a6120ae14/slf4j-api-1.7.36.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/2.7.5/fd04e228e6e21b7ad13c10ae29afd31868d842e5/spring-boot-2.7.5.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/jakarta.annotation/jakarta.annotation-api/1.3.5/59eb84ee0d616332ff44aba065f3888cf002cd2d/jakarta.annotation-api-1.3.5.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-context/5.3.23/530b36b2ce2c9e471c6a260c3f181bcd20325a58/spring-context-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-aop/5.3.23/30d0034ba29178e98781d85f51a7eb709a628e9b/spring-aop-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-beans/5.3.23/3bdefbf6042ed742cbe16f27d2d14cca9096a606/spring-beans-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-expression/5.3.23/3a676bf4b9bc42bd37ab5ad264acb6ceb63397a2/spring-expression-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-core/5.3.23/91407dc1106ea423c44150f3da1a0b4f8e25e5ca/spring-core-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.yaml/snakeyaml/1.30/8fde7fe2586328ac3c68db92045e1c8759125000/snakeyaml-1.30.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.springframework/spring-jcl/5.3.23/3c7eb5fcca67b611065f73ff4325e398f8b051a3/spring-jcl-5.3.23.jar
helloThere->/Users/MyDomainUserName/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.17.2/f42d6afa111b4dec5d2aea0fe2197240749a4ea6/log4j-api-2.17.2.jar
如果我“窺視”jar:
./source/java/myapproot/myapp-shared-resxex/build/libs/myapp-shared-resxex.jar
我確實看到了兩個 *.di.xml 文件。
然后如果我運行:
$ ./gradlew run
我繼續得到:
Caused by: java.io.FileNotFoundException: ./source/java/myapproot/myapp-toplayer-console-di-xml-one/build/resources/main/clientproxy.one.di.xml (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
at java.base/sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:86)
at java.base/sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:184)
at org.springframework.core.io.UrlResource.getInputStream(UrlResource.java:187)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333)
... 32 more
我的./gradle/wrapper/gradle-wrapper.properties 文件(為了完整性和了解我的 gradle-version)
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
.....
帶有代碼的 Github 回購。
https://github.com/granadacoder/gradle-multi-with-spring-bean-proof
“主要”分支...有一個工作的 spring-bean di.xml 設置。 “主要”分支與我上面的評論“上面的一切都很好”有關。
我有第二個分支(和一個 PR,所以你可以看到“差異”)。
分支:
和 PR(從功能分支到主分支以顯示“差異”)
https://github.com/granadacoder/gradle-multi-with-spring-bean-proof/pull/2/files
好的。
我找到了一個“舊”文檔頁面。
https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch04s07.html
我會張貼上面 URL 的引述,以防它“消失”.. 特別是因為它是“舊”文檔。
//開始文章引用
4.7.2.2 classpath*: 前綴在構建基於 XML 的應用程序上下文時,位置字符串可以使用特殊的 classpath*: 前綴:
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml"); 這個特殊前綴指定必須獲取所有與給定名稱匹配的類路徑資源(在內部,這實際上是通過 ClassLoader.getResources(...) 調用發生的),然后合並以形成最終的應用程序上下文定義。
[注意] 類路徑*:可移植性 通配符類路徑依賴於底層類加載器的 getResources() 方法。 由於現在大多數應用程序服務器都提供自己的類加載器實現,因此行為可能會有所不同,尤其是在處理 jar 文件時。 檢查類路徑* 是否有效的一個簡單測試是使用類加載器從類路徑上的 jar 中加載文件:getClass().getClassLoader().getResources("")。 使用具有相同名稱但位於兩個不同位置的文件嘗試此測試。 如果返回不適當的結果,請檢查應用程序服務器文檔以了解可能影響類加載器行為的設置。
“classpath*:”前綴也可以與位置路徑的 rest 中的 PathMatcher 模式組合,例如“classpath*:META-INF/*-beans.xml”。 在這種情況下,解析策略相當簡單:在最后一個非通配符路徑段上使用 ClassLoader.getResources() 調用來獲取 class 加載器層次結構中的所有匹配資源,然后關閉每個資源相同的 PathMatcher 解析策略上面描述的用於通配符子路徑。
//結束文章引用
所以我忘記了使用類路徑(在文件名等之前)的“字符串魔法”。
我能夠將我的 applicationContext.xml 文件更新為以下內容。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- below are "imports" to OTHER (spring-bean) di.xml files -->
<import resource="classpath:clientproxy.one.di.xml"/>
<import resource="classpath*:orchestrators.one.di.xml"/>
</beans>
您可以在下面的 SOF 問題/答案中了解使用“*”(在類路徑之后)之間的區別。
為清楚起見......我所做的只是將兩個 di.xml 文件“移動”到“其他”gradle/module-subproject。 我沒有使用我在原始問題中顯示的任何“myCoolConfigurationName”內容......作為我的“嘗試”之一。
“如此簡單”…………我為自己為此奮斗的日子感到高興和難以置信……
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.