Все примеры запускались на Maven 3.9.6
Если вы пользуетесь другой версией, то могут быть расхождения в фактическом поведении сборки. Если же используемая версия ниже 3.8.1, то примеры конфигурации точно потребуют внесения корректировок.
Предисловие
Работа на крупных проектах, например в банковском секторе, часто связана с необходимостью соблюдать различные требования, в том числе мириться с ограничениями от службы информационной безопасности. Одним из таких ограничений стал запрет на использование артефактов с центрального maven репозитория.
Конечно, речь не идет о полном отказе от общедоступных библиотек. Но в большинстве случаев уже не получится просто взять понравившуюся версию, которая опубликована на central.
Кто-то автоматизирует процесс загрузки новых зависимостей. Только работает она уже не через простое проксирование на внутреннем хранилище, а с проведением различных проверок, которые не всегда могут завершаться успехом. Кто-то поступает более кардинально и вводит целый процесс добавления новых артефактов, который не обходится без заведения специальных запросов и “ручного” рассмотрения.
Можно долго дискутировать над разумностью таких подходов, но фактически остается только подстраиваться под обстоятельства. И тут можно столкнуться с неприятной ситуацией, когда при локальной разработке артефакты загрузятся, а на CI окажется, что их значительная часть отсутствует.
Недавно первой задачей на новом проекте стало значительное обновление стека имеющихся микросервисов. Целью был переход на Spring Boot 3 версии, а вот текущий стек: Java 8, Spring Boot 2.5, Camunda 7.12 и т.д. Местами могли попадаться раритетные версии артефактов, потому что на старте проектов кто-то копипастил зависимости из своих старых решений.
При этом предоставленный settings.xml
содержал несколько репозиториев с внутреннего Nexus,
а об отсутствии какого-либо полноценного проксирования центральных репозиториев я узнал только по факту ошибок на CI.
Откуда берется Maven Central
Создадим практически минимальный pom.xml
и settings.xml
, в котором добавлено два внутренних репозитория:
- Общие артефакты всей организации: private-nexus-common.
- Артефакты подразделения, на проекте которого мы работаем: private-nexus-subdivision.
Любые внешние артефакты загружаются в private-nexus-common по итогам достаточно долгого процесса. При этом закончиться он может и формулировкой “Не видим необходимости в добавлении артефакта”.
Давайте посмотрим на полный состав pom, по которому будет происходить сборка.
1akorolev.dev maven
2$ mvn help:effective-pom -Dverbose -Doutput=effective-pom.xml -s ~/.m2/settings.xml
3Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
4[INFO] Scanning for projects...
5[INFO]
6[INFO] -------------------< dev.akorolev.maven:simple-pom >--------------------
7[INFO] Building simple-pom 0.1.0
8[INFO] from pom.xml
9[INFO] --------------------------------[ jar ]---------------------------------
10[INFO]
11[INFO] --- help:3.4.0:effective-pom (default-cli) @ simple-pom ---
12[INFO] Effective-POM written to: D:\repositories\articles\maven\effective-pom.xml
13[INFO] ------------------------------------------------------------------------
14[INFO] BUILD SUCCESS
15[INFO] ------------------------------------------------------------------------
16[INFO] Total time: 0.682 s
17[INFO] Finished at: 2024-03-19T21:19:22+04:00
18[INFO] ------------------------------------------------------------------------
1<?xml version="1.0" encoding="UTF-8"?>
2<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
5
6 <localRepository>D:/.m2/local_repository</localRepository>
7 <profiles>
8 <profile>
9 <activation>
10 <activeByDefault>true</activeByDefault>
11 </activation>
12 <repositories>
13 <repository>
14 <id>private-nexus-common</id>
15 <name>Private Nexus Common Repository</name>
16 <url>https://akorolev.dev/repository/common/</url>
17 </repository>
18 <repository>
19 <id>private-nexus-subdivision</id>
20 <name>Private Nexus Subdivision Repository</name>
21 <url>https://akorolev.dev/repository/subdivision/</url>
22 </repository>
23 </repositories>
24 <pluginRepositories>
25 <pluginRepository>
26 <id>private-nexus-common</id>
27 <name>Private Nexus Common Plugin Repository</name>
28 <url>https://akorolev.dev/repository/common/</url>
29 </pluginRepository>
30 </pluginRepositories>
31 </profile>
32 </profiles>
33</settings>
1<project xmlns="http://maven.apache.org/POM/4.0.0"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5
6 <groupId>dev.akorolev.maven</groupId>
7 <artifactId>simple-pom</artifactId>
8 <version>0.1.0</version>
9
10 <properties>
11 <java.version>17</java.version>
12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13 </properties>
14</project>
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- ====================================================================== -->
3<!-- -->
4<!-- Generated by Maven Help Plugin -->
5<!-- See: https://maven.apache.org/plugins/maven-help-plugin/ -->
6<!-- -->
7<!-- ====================================================================== -->
8<!-- ====================================================================== -->
9<!-- -->
10<!-- Effective POM for project 'dev.akorolev.maven:simple-pom:jar:0.1.0' -->
11<!-- -->
12<!-- ====================================================================== -->
13<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
15 <modelVersion>4.0.0</modelVersion> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 4 -->
16 <groupId>dev.akorolev.maven</groupId> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 6 -->
17 <artifactId>simple-pom</artifactId> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 7 -->
18 <version>0.1.0</version> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 8 -->
19 <properties>
20 <java.version>17</java.version> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 11 -->
21 <project.build.sourceEncoding>UTF-8
22 </project.build.sourceEncoding> <!-- dev.akorolev.maven:simple-pom:0.1.0, line 12 -->
23 </properties>
24 <repositories>
25 <repository>
26 <id>private-nexus-common</id>
27 <name>Private Nexus Common Repository</name>
28 <url>https://akorolev.dev/repository/common/</url>
29 </repository>
30 <repository>
31 <id>private-nexus-subdivision</id>
32 <name>Private Nexus Subdivision Repository</name>
33 <url>https://akorolev.dev/repository/subdivision/</url>
34 </repository>
35 <repository>
36 <snapshots>
37 <enabled>false</enabled> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 33 -->
38 </snapshots>
39 <id>central</id> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 28 -->
40 <name>Central Repository</name> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 29 -->
41 <url>https://repo.maven.apache.org/maven2
42 </url> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 30 -->
43 </repository>
44 </repositories>
45 <pluginRepositories>
46 <pluginRepository>
47 <id>private-nexus-common</id>
48 <name>Private Nexus Common Plugin Repository</name>
49 <url>https://akorolev.dev/repository/common/</url>
50 </pluginRepository>
51 <pluginRepository>
52 <releases>
53 <updatePolicy>never
54 </updatePolicy> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 48 -->
55 </releases>
56 <snapshots>
57 <enabled>false</enabled> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 45 -->
58 </snapshots>
59 <id>central</id> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 40 -->
60 <name>Central Repository</name> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 41 -->
61 <url>https://repo.maven.apache.org/maven2
62 </url> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 42 -->
63 </pluginRepository>
64 </pluginRepositories>
65 <build>
66 <sourceDirectory>D:\repositories\articles\maven\src\main\java
67 </sourceDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 58 -->
68 <scriptSourceDirectory>D:\repositories\articles\maven\src\main\scripts
69 </scriptSourceDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 59 -->
70 <testSourceDirectory>D:\repositories\articles\maven\src\test\java
71 </testSourceDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 60 -->
72 <outputDirectory>D:\repositories\articles\maven\target\classes
73 </outputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 55 -->
74 <testOutputDirectory>D:\repositories\articles\maven\target\test-classes
75 </testOutputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 57 -->
76 <resources>
77 <resource>
78 <directory>D:\repositories\articles\maven\src\main\resources
79 </directory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 63 -->
80 </resource>
81 </resources>
82 <testResources>
83 <testResource>
84 <directory>D:\repositories\articles\maven\src\test\resources
85 </directory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 68 -->
86 </testResource>
87 </testResources>
88 <directory>D:\repositories\articles\maven\target
89 </directory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 54 -->
90 <finalName>simple-pom-0.1.0</finalName> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 56 -->
91 <pluginManagement>
92 <plugins>
93 <plugin>
94 <artifactId>maven-antrun-plugin
95 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 76 -->
96 <version>3.1.0</version> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 77 -->
97 </plugin>
98 <plugin>
99 <artifactId>maven-assembly-plugin
100 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 80 -->
101 <version>3.6.0</version> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 81 -->
102 </plugin>
103 <plugin>
104 <artifactId>maven-dependency-plugin
105 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 84 -->
106 <version>3.6.1</version> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 85 -->
107 </plugin>
108 <plugin>
109 <artifactId>maven-release-plugin
110 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 88 -->
111 <version>3.0.1</version> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 89 -->
112 </plugin>
113 </plugins>
114 </pluginManagement>
115 <plugins>
116 <plugin>
117 <artifactId>maven-clean-plugin
118 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
119 <version>3.2.0</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
120 <executions>
121 <execution>
122 <id>default-clean</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
123 <phase>clean</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
124 <goals>
125 <goal>clean</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
126 </goals>
127 </execution>
128 </executions>
129 </plugin>
130 <plugin>
131 <artifactId>maven-resources-plugin
132 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
133 <version>3.3.1</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
134 <executions>
135 <execution>
136 <id>default-testResources
137 </id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
138 <phase>process-test-resources
139 </phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
140 <goals>
141 <goal>testResources
142 </goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
143 </goals>
144 </execution>
145 <execution>
146 <id>default-resources
147 </id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
148 <phase>process-resources
149 </phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
150 <goals>
151 <goal>resources
152 </goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
153 </goals>
154 </execution>
155 </executions>
156 </plugin>
157 <plugin>
158 <artifactId>maven-jar-plugin
159 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
160 <version>3.3.0</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
161 <executions>
162 <execution>
163 <id>default-jar</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
164 <phase>package</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
165 <goals>
166 <goal>jar</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
167 </goals>
168 </execution>
169 </executions>
170 </plugin>
171 <plugin>
172 <artifactId>maven-compiler-plugin
173 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
174 <version>3.11.0</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
175 <executions>
176 <execution>
177 <id>default-compile</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
178 <phase>compile</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
179 <goals>
180 <goal>compile</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
181 </goals>
182 </execution>
183 <execution>
184 <id>default-testCompile
185 </id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
186 <phase>test-compile
187 </phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
188 <goals>
189 <goal>testCompile
190 </goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
191 </goals>
192 </execution>
193 </executions>
194 </plugin>
195 <plugin>
196 <artifactId>maven-surefire-plugin
197 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
198 <version>3.2.2</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
199 <executions>
200 <execution>
201 <id>default-test</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
202 <phase>test</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
203 <goals>
204 <goal>test</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
205 </goals>
206 </execution>
207 </executions>
208 </plugin>
209 <plugin>
210 <artifactId>maven-install-plugin
211 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
212 <version>3.1.1</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
213 <executions>
214 <execution>
215 <id>default-install</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
216 <phase>install</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
217 <goals>
218 <goal>install</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
219 </goals>
220 </execution>
221 </executions>
222 </plugin>
223 <plugin>
224 <artifactId>maven-deploy-plugin
225 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
226 <version>3.1.1</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
227 <executions>
228 <execution>
229 <id>default-deploy</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
230 <phase>deploy</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
231 <goals>
232 <goal>deploy</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
233 </goals>
234 </execution>
235 </executions>
236 </plugin>
237 <plugin>
238 <artifactId>maven-site-plugin
239 </artifactId> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
240 <version>3.12.1</version> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
241 <executions>
242 <execution>
243 <id>default-site</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
244 <phase>site</phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
245 <goals>
246 <goal>site</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
247 </goals>
248 <configuration>
249 <outputDirectory>D:\repositories\articles\maven\target\site
250 </outputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 96 -->
251 <reportPlugins>
252 <reportPlugin>
253 <groupId>org.apache.maven.plugins
254 </groupId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
255 <artifactId>maven-project-info-reports-plugin
256 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
257 </reportPlugin>
258 </reportPlugins>
259 </configuration>
260 </execution>
261 <execution>
262 <id>default-deploy</id> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
263 <phase>site-deploy
264 </phase> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
265 <goals>
266 <goal>deploy</goal> <!-- org.apache.maven:maven-core:3.9.6:default-lifecycle-bindings -->
267 </goals>
268 <configuration>
269 <outputDirectory>D:\repositories\articles\maven\target\site
270 </outputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 96 -->
271 <reportPlugins>
272 <reportPlugin>
273 <groupId>org.apache.maven.plugins
274 </groupId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
275 <artifactId>maven-project-info-reports-plugin
276 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
277 </reportPlugin>
278 </reportPlugins>
279 </configuration>
280 </execution>
281 </executions>
282 <configuration>
283 <outputDirectory>D:\repositories\articles\maven\target\site
284 </outputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 96 -->
285 <reportPlugins>
286 <reportPlugin>
287 <groupId>org.apache.maven.plugins
288 </groupId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
289 <artifactId>maven-project-info-reports-plugin
290 </artifactId> <!-- org.apache.maven:maven-model-builder:3.9.6:reporting-converter -->
291 </reportPlugin>
292 </reportPlugins>
293 </configuration>
294 </plugin>
295 </plugins>
296 </build>
297 <reporting>
298 <outputDirectory>D:\repositories\articles\maven\target\site
299 </outputDirectory> <!-- org.apache.maven:maven-model-builder:3.9.6:super-pom, line 96 -->
300 </reporting>
301</project>
Данных заметно больше, чем мы создали самостоятельно. И главное, что добавились записи для репозитория central. То есть, если какой-то артефакт не будет найден на private-nexus-common или private-nexus-subdivision, то произойдет попытка его загрузки из центрального хранилища.
Эффективный pom.xml — это результат слияния так называемого Super POM, нашего файла проекта и используемых активных профилей из файла настроек.
Super POM можно найти внутри домашней директории используемого maven. Он располагается в lib/maven-model-builder-3.9.6.jar
org/apache/maven/model/pom-4.0.0.xml
1<?xml version="1.0" encoding="UTF-8"?>
2
3<!--
4Licensed to the Apache Software Foundation (ASF) under one
5or more contributor license agreements. See the NOTICE file
6distributed with this work for additional information
7regarding copyright ownership. The ASF licenses this file
8to you under the Apache License, Version 2.0 (the
9"License"); you may not use this file except in compliance
10with the License. You may obtain a copy of the License at
11
12 http://www.apache.org/licenses/LICENSE-2.0
13
14Unless required by applicable law or agreed to in writing,
15software distributed under the License is distributed on an
16"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17KIND, either express or implied. See the License for the
18specific language governing permissions and limitations
19under the License.
20-->
21
22<!-- START SNIPPET: superpom -->
23<project>
24 <modelVersion>4.0.0</modelVersion>
25
26 <repositories>
27 <repository>
28 <id>central</id>
29 <name>Central Repository</name>
30 <url>https://repo.maven.apache.org/maven2</url>
31 <layout>default</layout>
32 <snapshots>
33 <enabled>false</enabled>
34 </snapshots>
35 </repository>
36 </repositories>
37
38 <pluginRepositories>
39 <pluginRepository>
40 <id>central</id>
41 <name>Central Repository</name>
42 <url>https://repo.maven.apache.org/maven2</url>
43 <layout>default</layout>
44 <snapshots>
45 <enabled>false</enabled>
46 </snapshots>
47 <releases>
48 <updatePolicy>never</updatePolicy>
49 </releases>
50 </pluginRepository>
51 </pluginRepositories>
52
53 <build>
54 <directory>${project.basedir}/target</directory>
55 <outputDirectory>${project.build.directory}/classes</outputDirectory>
56 <finalName>${project.artifactId}-${project.version}</finalName>
57 <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
58 <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
59 <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
60 <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
61 <resources>
62 <resource>
63 <directory>${project.basedir}/src/main/resources</directory>
64 </resource>
65 </resources>
66 <testResources>
67 <testResource>
68 <directory>${project.basedir}/src/test/resources</directory>
69 </testResource>
70 </testResources>
71 <pluginManagement>
72 <!-- NOTE: These plugins will be removed from future versions of the super POM -->
73 <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
74 <plugins>
75 <plugin>
76 <artifactId>maven-antrun-plugin</artifactId>
77 <version>3.1.0</version>
78 </plugin>
79 <plugin>
80 <artifactId>maven-assembly-plugin</artifactId>
81 <version>3.6.0</version>
82 </plugin>
83 <plugin>
84 <artifactId>maven-dependency-plugin</artifactId>
85 <version>3.6.1</version>
86 </plugin>
87 <plugin>
88 <artifactId>maven-release-plugin</artifactId>
89 <version>3.0.1</version>
90 </plugin>
91 </plugins>
92 </pluginManagement>
93 </build>
94
95 <reporting>
96 <outputDirectory>${project.build.directory}/site</outputDirectory>
97 </reporting>
98
99 <profiles>
100 <!-- NOTE: The release profile will be removed from future versions of the super POM -->
101 <profile>
102 <id>release-profile</id>
103
104 <activation>
105 <property>
106 <name>performRelease</name>
107 <value>true</value>
108 </property>
109 </activation>
110
111 <build>
112 <plugins>
113 <plugin>
114 <inherited>true</inherited>
115 <artifactId>maven-source-plugin</artifactId>
116 <executions>
117 <execution>
118 <id>attach-sources</id>
119 <goals>
120 <goal>jar-no-fork</goal>
121 </goals>
122 </execution>
123 </executions>
124 </plugin>
125 <plugin>
126 <inherited>true</inherited>
127 <artifactId>maven-javadoc-plugin</artifactId>
128 <executions>
129 <execution>
130 <id>attach-javadocs</id>
131 <goals>
132 <goal>jar</goal>
133 </goals>
134 </execution>
135 </executions>
136 </plugin>
137 <plugin>
138 <inherited>true</inherited>
139 <artifactId>maven-deploy-plugin</artifactId>
140 </plugin>
141 </plugins>
142 </build>
143 </profile>
144 </profiles>
145
146</project>
147 <!-- END SNIPPET: superpom -->
Именно данный файл является причиной использования в любом проекте центрального репозитория.
Также в нём прописана директория src/main/java
, как место для создания файлов с исходным кодом и прочие настройки по умолчанию.
Варианты решения проблемы
Все варианты основываются на создании отдельного конфигурационного файла maven. Альтернативы из серии “заблокировать адрес на уровне hosts или маршрутов сети” в большинстве случаев не подходят, так как ограничение надо реализовать только для отдельного проекта.
По запросу Disable Maven central
чаще всего обсуждают два варианта:
- переопределение адреса
- указание зеркала
Сперва их и рассмотрим.
Переопределение адреса репозитория central
Эффективный POM строится методом наследования. Такую аналогию с java.lang.Object даже содержит
официальная документация Maven
.
Некоторые называют переопределение более логичным, когда речь идет именно про запрет central.
Можно встретить аргументы, что зеркала предназначены для “проектных репозиториев”, которые добавлены непосредственно в pom.xml
.
Приводятся доводы, что изменить их адрес можно только так, в отличие от репозиториев, которые прописаны в файле глобальных настроек.
По факту дела обстоят немного иначе. Произведем следующие изменения:
- заменим идентификаторы private-nexus-common на central, так как именно сюда загружаются артефакты после успешного рассмотрения заявки
- добавим в
pom.xml
дополнительный репозиторий camunda (camunda-bpm-nexus) - в настройках переопределим адрес для репозитория camunda-bpm-nexus
- в настройках переопределим свойство
java.version
на значение 21
В итоге получим effective-pom.xml
, в котором применились все внесенные изменения из файла настроек.
1<?xml version="1.0" encoding="UTF-8"?>
2<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
5
6 <localRepository>D:/.m2/local_repository</localRepository>
7 <profiles>
8 <profile>
9 <activation>
10 <activeByDefault>true</activeByDefault>
11 </activation>
12 <properties>
13 <java.version>21</java.version>
14 </properties>
15 <repositories>
16 <repository>
17 <id>central</id>
18 <name>Private Nexus Common Repository</name>
19 <url>https://akorolev.dev/repository/common/</url>
20 </repository>
21 <repository>
22 <id>camunda-bpm-nexus</id>
23 <name>Private Nexus Common Repository</name>
24 <url>https://akorolev.dev/repository/common/</url>
25 </repository>
26 <repository>
27 <id>private-nexus-subdivision</id>
28 <name>Private Nexus Subdivision Repository</name>
29 <url>https://akorolev.dev/repository/subdivision/</url>
30 </repository>
31 </repositories>
32 <pluginRepositories>
33 <pluginRepository>
34 <id>central</id>
35 <name>Private Nexus Common Plugin Repository</name>
36 <url>https://akorolev.dev/repository/common/</url>
37 </pluginRepository>
38 </pluginRepositories>
39 </profile>
40 </profiles>
41</settings>
1<project xmlns="http://maven.apache.org/POM/4.0.0"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5
6 <groupId>dev.akorolev.maven</groupId>
7 <artifactId>simple-pom</artifactId>
8 <version>0.1.0</version>
9
10 <properties>
11 <java.version>17</java.version>
12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13 </properties>
14
15 <repositories>
16 <repository>
17 <id>camunda-bpm-nexus</id>
18 <name>camunda-bpm-nexus</name>
19 <url>https://artifacts.camunda.com/artifactory/public/</url>
20 </repository>
21 </repositories>
22</project>
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>dev.akorolev.maven</groupId>
6 <artifactId>simple-pom</artifactId>
7 <version>0.1.0</version>
8 <properties>
9 <java.version>21</java.version>
10 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11 </properties>
12 <repositories>
13 <repository>
14 <id>central</id>
15 <name>Private Nexus Common Repository</name>
16 <url>https://akorolev.dev/repository/common/</url>
17 </repository>
18 <repository>
19 <id>camunda-bpm-nexus</id>
20 <name>Private Nexus Common Repository</name>
21 <url>https://akorolev.dev/repository/common/</url>
22 </repository>
23 <repository>
24 <id>private-nexus-subdivision</id>
25 <name>Private Nexus Subdivision Repository</name>
26 <url>https://akorolev.dev/repository/subdivision/</url>
27 </repository>
28 </repositories>
29 <pluginRepositories>
30 <pluginRepository>
31 <id>central</id>
32 <name>Private Nexus Common Plugin Repository</name>
33 <url>https://akorolev.dev/repository/common/</url>
34 </pluginRepository>
35 </pluginRepositories>
36 <!-- Удалены блоки <build> и <reporting>-->
37</project>
На первый взгляд данное решение выглядит подходящим, но надо учитывать один важный момент.
Когда происходит загрузка артефакта в локальный репозиторий D:/.m2/local_repository
, то сохраняется метаинформация об идентификаторе источника в файле _remote.repositories
.
Например, для org/apache/maven/shared/maven-shared-utils/3.3.4
его содержимое поменяется следующим образом:
1#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
2#Wed Mar 20 05:24:45 GMT+04:00 2024
3maven-shared-utils-3.3.4.pom>private-nexus-common=
4maven-shared-utils-3.3.4.jar>private-nexus-common=
1#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
2#Wed Mar 20 05:27:19 GMT+04:00 2024
3maven-shared-utils-3.3.4.pom>private-nexus-common=
4maven-shared-utils-3.3.4.jar>central=
5maven-shared-utils-3.3.4.jar>private-nexus-common=
6maven-shared-utils-3.3.4.pom>central=
То есть, в первый раз происходила загрузка артефакта из private-nexus-common. Но при втором построении maven проверяет, что репозиторий private-nexus-common отсутствует в текущем контексте сборки. Поэтому производится повторный поиск артефакта среди активного набора репозиториев.
В таком случае в логах будет выводиться соответствующее уведомление:
1[INFO] Artifact org.apache.maven.shared:maven-shared-utils:pom:3.3.4 is present in the local repository, but cached from a remote repository ID that is unavailable in current build context, verifying that is downloadable from [central (https://akorolev.dev/repository/common/, default, releases+snapshots)]
2Downloading from central: https://akorolev.dev/repository/common/org/apache/maven/shared/maven-shared-utils/3.3.4/maven-shared-utils-3.3.4.pom
3Downloaded from central: https://akorolev.dev/repository/common/org/apache/maven/shared/maven-shared-utils/3.3.4/maven-shared-utils-3.3.4.pom (0 B at 0 B/s)
4[INFO] Artifact org.apache.maven.shared:maven-shared-utils:jar:3.3.4 is present in the local repository, but cached from a remote repository ID that is unavailable in current build context, verifying that is downloadable from [central (https://akorolev.dev/repository/common/, default, releases+snapshots)]
5Downloading from central: https://akorolev.dev/repository/common/org/apache/maven/shared/maven-shared-utils/3.3.4/maven-shared-utils-3.3.4.jar
6Downloaded from central: https://akorolev.dev/repository/common/org/apache/maven/shared/maven-shared-utils/3.3.4/maven-shared-utils-3.3.4.jar (0 B at 0 B/s)
Но если у вас будет два независимых проекта, в которых central будет переопределен разными адресами, то упомянутый механизм проверки доступности артефакта может отработать некорректно. Может возникнуть ошибочное решение, что зависимость ранее была загружена из доступного источника, хотя по факту она может оказаться вне доступа для текущего контекста сборки.
Использование зеркала для репозитория central
Можно заменить переопределение репозиториев на добавление зеркала.
Модель POM не предполагает наличие mirror
элементов, поэтому они в текст эффективного pom не добавляются.
1<?xml version="1.0" encoding="UTF-8"?>
2<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
5
6 <localRepository>D:/.m2/local_repository</localRepository>
7 <mirrors>
8 <mirror>
9 <id>private-nexus-mock-external</id>
10 <mirrorOf>central,camunda-bpm-nexus</mirrorOf>
11 <name>Repository to mock external</name>
12 <url>https://akorolev.dev/repository/common/</url>
13 </mirror>
14 </mirrors>
15 <profiles>
16 <profile>
17 <activation>
18 <activeByDefault>true</activeByDefault>
19 </activation>
20 <properties>
21 <java.version>21</java.version>
22 </properties>
23 <repositories>
24 <repository>
25 <id>private-nexus-subdivision</id>
26 <name>Private Nexus Subdivision Repository</name>
27 <url>https://akorolev.dev/repository/subdivision/</url>
28 </repository>
29 </repositories>
30 </profile>
31 </profiles>
32</settings>
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>dev.akorolev.maven</groupId>
6 <artifactId>simple-pom</artifactId>
7 <version>0.1.0</version>
8 <properties>
9 <java.version>21</java.version>
10 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11 </properties>
12 <repositories>
13 <repository>
14 <id>private-nexus-subdivision</id>
15 <name>Private Nexus Subdivision Repository</name>
16 <url>https://akorolev.dev/repository/subdivision/</url>
17 </repository>
18 <repository>
19 <id>camunda-bpm-nexus</id>
20 <name>camunda-bpm-nexus</name>
21 <url>https://artifacts.camunda.com/artifactory/public/</url>
22 </repository>
23 <repository>
24 <snapshots>
25 <enabled>false</enabled>
26 </snapshots>
27 <id>central</id>
28 <name>Central Repository</name>
29 <url>https://repo.maven.apache.org/maven2</url>
30 </repository>
31 </repositories>
32 <pluginRepositories>
33 <pluginRepository>
34 <releases>
35 <updatePolicy>never</updatePolicy>
36 </releases>
37 <snapshots>
38 <enabled>false</enabled>
39 </snapshots>
40 <id>central</id>
41 <name>Central Repository</name>
42 <url>https://repo.maven.apache.org/maven2</url>
43 </pluginRepository>
44 </pluginRepositories>
45 <!-- Удалены блоки <build> и <reporting>-->
46</project>
Но в метаинформацию, для указанного ранее артефакта, будет добавляться уже не идентификатор репозитория, а идентификатор зеркала: private-nexus-mock-external. Это устранит возможность возникновения проблемы с некорректным определением доступности в текущем контексте сборки.
Блокировка репозитория central
В целом, предыдущий вариант решает необходимую задачу и можно воспользоваться им.
Есть только “концептуальный” момент, что https://akorolev.dev/repository/common/
— это не зеркало внешних репозиториев, а внутреннее хранилище организации.
В первую очередь пространство предназначено для корпоративных библиотек общего назначения, в которое дополнительно загружаются отдельные внешние зависимости по мере потребностей.
Если используется Maven версии 3.8.1
и выше, то можно попробовать альтернативный вариант.
В данном релизе была обновлена xml-модель файла настроек (
v1.2.0
) и элемент mirror
обзавелся вложенным blocked
.
1<?xml version="1.0" encoding="UTF-8"?>
2<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
5
6 <localRepository>D:/.m2/local_repository</localRepository>
7 <mirrors>
8 <mirror>
9 <id>maven-central-blocker</id>
10 <mirrorOf>central</mirrorOf>
11 <name>Pseudo repository to block the central repository</name>
12 <url>http://0.0.0.0/</url>
13 <blocked>true</blocked>
14 </mirror>
15 </mirrors>
16 <profiles>
17 <profile>
18 <activation>
19 <activeByDefault>true</activeByDefault>
20 </activation>
21 <properties>
22 <java.version>21</java.version>
23 </properties>
24 <repositories>
25 <repository>
26 <id>private-nexus-common</id>
27 <name>Private Nexus Common Repository</name>
28 <url>https://akorolev.dev/repository/common/</url>
29 </repository>
30 <repository>
31 <id>private-nexus-subdivision</id>
32 <name>Private Nexus Subdivision Repository</name>
33 <url>https://akorolev.dev/repository/subdivision/</url>
34 </repository>
35 </repositories>
36 <pluginRepositories>
37 <pluginRepository>
38 <id>private-nexus-common</id>
39 <name>Private Nexus Common Plugin Repository</name>
40 <url>https://akorolev.dev/repository/common/</url>
41 </pluginRepository>
42 </pluginRepositories>
43 </profile>
44 </profiles>
45</settings>
Blocked mirror for repositories: [central (https://repo.maven.apache.org/maven2, default, releases)]
, а сборка будет падать в ошибку.Но на данном варианте тоже была замечена проблема при использовании достаточно старых версий плагинов.
Например, flatten-maven-plugin
версии 1.1.0
(21 декабря 2018 г.) стабильно пытался проверить доступность через заблокированное зеркало,
так как ошибочно считал, что ранее закешированный артефакт загружен с недоступного в текущем контексте репозитория.
Хотя его банальное обновление до следующей версии 1.2.1
(18 января 2020 г.) устранило данную проблему и проект начинал собираться корректно.
Послесловие
По итогу, только на втором способе настроек я не заметил “подводных камней”.
Хотя третий вариант в большей степени соответствует формулировке “запрет на использование”. И в данный момент я остановился на нём, чтобы производить сборку микросервисов на текущем проекте.
Знаете лучшую альтернативу? Поделитесь ей в комментариях.
Источник изображения в заголовке Unsplash. Автор Jacob Li .