← Назад к вопросам

Что происходит на этапе компиляции в Maven

1.7 Middle🔥 171 комментариев
#Docker, Kubernetes и DevOps#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Этапы компиляции в Maven

Maven — это инструмент для управления проектами Java, который включает мощную систему компиляции кода. Процесс компиляции в Maven состоит из нескольких этапов, каждый из которых выполняет важную функцию.

1. Жизненный цикл Maven (Build Lifecycle)

Compile Lifecycle:
   validate
     ↓
   initialize
     ↓
   generate-sources      ← Генерация исходного кода
     ↓
   process-sources       ← Обработка исходного кода
     ↓
   generate-resources    ← Генерация ресурсов
     ↓
   process-resources     ← Копирование/обработка ресурсов
     ↓
   compile               ← КОМПИЛЯЦИЯ JAVA КОДА
     ↓
   process-classes       ← Постобработка скомпилированного кода
     ↓
   generate-test-sources ← Генерация тестовых источников
     ↓
   process-test-sources  ← Обработка тестовых источников
     ↓
   generate-test-resources
     ↓
   process-test-resources
     ↓
   test-compile          ← Компиляция тестов
     ↓
   process-test-classes
     ↓
   test                  ← Запуск тестов
     ↓
   package               ← Упаковка (JAR/WAR/EAR)
     ↓
   install               ← Установка в локальный репозиторий
     ↓
   deploy                ← Развёртывание в удалённый репозиторий

2. Этап compile (основная компиляция)

// Maven выполняет следующее:

// 1. Сканирует исходные файлы
src/main/java/**/*.java

// 2. Находит все зависимости (dependencies)
// из pom.xml и загружает их в классpath

// 3. Вызывает Java компилятор (javac)
javac -d target/classes \
      -classpath [dependencies] \
      src/main/java/**/*.java

// 4. Генерирует .class файлы
target/classes/com/example/MyClass.class

3. Процесс обработки ресурсов (process-resources)

// Перед компиляцией Maven обрабатывает ресурсы

// Входящие ресурсы:
src/main/resources/
  ├── application.properties
  ├── application.yml
  ├── logback.xml
  └── schema.sql

// Выходящие ресурсы (в целевую папку):
target/classes/
  ├── application.properties
  ├── application.yml
  ├── logback.xml
  └── schema.sql

// Особенность: Maven может подставлять переменные
// ${project.version}, ${project.name} и т.д.

4. Фильтрация ресурсов (Resource Filtering)

<!-- pom.xml -->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <!-- Включить фильтрацию свойств -->
        </resource>
    </resources>
</build>
# src/main/resources/app.properties (ПЕРЕД обработкой)
app.name=${project.name}
app.version=${project.version}
app.buildTime=${maven.build.timestamp}

# target/classes/app.properties (ПОСЛЕ обработки)
app.name=MyApp
app.version=1.0.0
app.buildTime=2026-03-23T12:00:00Z

5. Компилятор по умолчанию (Maven Compiler)

<!-- pom.xml -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>           <!-- Исходная Java версия -->
                <target>17</target>           <!-- Целевая Java версия -->
                <encoding>UTF-8</encoding>    <!-- Кодировка файлов -->
                <debug>true</debug>           <!-- Дебаг информация -->
                <compilerArgs>
                    <arg>-parameters</arg>    <!-- Сохранять имена параметров -->
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

6. Генерация исходных файлов (generate-sources)

<!-- Пример: автоматическая генерация кода из схемы БД -->
<plugin>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen-maven</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
                <!-- Конфигурация для генерации JOOQ классов -->
            </configuration>
        </execution>
    </executions>
</plugin>
// Сгенерированный код (example)
public class UsersRecord extends Record5<...> {
    // Автоматически сгенерировано из схемы БД
    public Field<Integer> ID;
    public Field<String> NAME;
    public Field<String> EMAIL;
    // ...
}

7. Обработка аннотаций (annotation processing)

<!-- pom.xml -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.30</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>
// Исходный код с аннотациями
@Data  // Lombok аннотация
public class User {
    private String name;
    private int age;
}

// После обработки аннотаций компилятор генерирует:
public class User {
    private String name;
    private int age;
    
    // Сгенерировано Lombok processor
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return this.age; }
    public void setAge(int age) { this.age = age; }
    // ... equals(), hashCode(), toString()
}

8. Определение зависимостей (dependency resolution)

<!-- pom.xml -->
<dependencies>
    <!-- На этапе compile эти зависимости добавятся в classpath -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.2.0</version>
        <scope>compile</scope>  <!-- По умолчанию -->
    </dependency>
    
    <!-- test зависимости не входят в classpath компиляции -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Scope в Maven:

scope="compile"   → Включена при компиляции и запуске
scope="test"      → Только при тестировании
scope="provided"  → Предоставляется контейнером (servlet-api)
scope="runtime"   → Требуется при запуске, но не при компиляции
scope="optional"  → Опциональная зависимость

9. Порядок выполнения фаз

# При команде: mvn clean compile

# 1. Clean lifecycle (выполняется из-за clean)
mvn clean:
  - Удаляет target/

# 2. Default lifecycle (выполняется до compile включительно)
mvn compile:
  - validate
  - initialize
  - generate-sources
  - process-sources
  - generate-resources
  - process-resources       ← Копирование ресурсов
  - compile                 ← КОМПИЛЯЦИЯ

# Результат:
# target/classes/com/example/
#   ├── MyClass.class
#   ├── MyApp.class
#   └── ...
# target/classes/
#   ├── application.properties
#   ├── logback.xml
#   └── ...

10. Обработка зависимостей (transitive dependencies)

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.2.0</version>
</dependency>

<!-- Spring-boot-starter-web включает:
  - spring-webmvc
  - spring-boot-starter-json
  - spring-boot-starter-tomcat
  - и многие другие...
-->
# Просмотр дерева зависимостей
mvn dependency:tree

# Вывод:
# org.example:myapp:jar:1.0.0
# └── org.springframework.boot:spring-boot-starter-web:jar:3.2.0:compile
#     ├── org.springframework.boot:spring-boot-starter:jar:3.2.0:compile
#     │   ├── org.springframework.boot:spring-boot:jar:3.2.0:compile
#     │   ├── org.springframework.boot:spring-boot-autoconfigure:jar:3.2.0:compile
#     │   └── org.springframework:spring-context:jar:6.1.0:compile
#     ├── org.springframework.boot:spring-boot-starter-json:jar:3.2.0:compile
#     └── org.springframework.boot:spring-boot-starter-tomcat:jar:3.2.0:compile

11. Классификация ошибок при компиляции

// Ошибка компиляции (не может быть запущена)
public class Syntax {
    public void test( {
        // Missing ) - синтаксическая ошибка
    }
}
// ERROR: Syntax error, insert ")" to complete FormalParameterList

// Ошибка типов
public class TypeMismatch {
    public void test() {
        String s = 42;  // int не совместим с String
    }
}
// ERROR: incompatible types: int cannot be converted to String

// Ошибка символа (неизвестный класс)
public class UnknownSymbol {
    public void test() {
        NonExistentClass obj = new NonExistentClass();
    }
}
// ERROR: cannot find symbol: class NonExistentClass

12. Оптимизация компиляции

<!-- Использование incremental compilation -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.11.0</version>
    <configuration>
        <source>17</source>
        <target>17</target>
        <!-- Параллельная компиляция (Java 9+) -->
        <fork>true</fork>
        <meminitial>512m</meminitial>
        <maxmem>1024m</maxmem>
        <compilerArgs>
            <arg>-J-Xms512m</arg>
            <arg>-J-Xmx1024m</arg>
        </compilerArgs>
    </configuration>
</plugin>
# Пересборка только изменённых файлов
mvn compile

# Полная пересборка
mvn clean compile

# Компиляция с параллельным выполнением
mvn -T 1C compile  # T 1C = 1 thread per core

Best Practices

// 1. Всегда указывай версии Java
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

// 2. Включай обработку аннотаций
<configuration>
    <annotationProcessorPaths>
        <!-- Lombok и другие -->
    </annotationProcessorPaths>
</configuration>

// 3. Использование BOM для управления версиями
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

// 4. Фильтруй ненужные зависимости
<exclusions>
    <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion>
</exclusions>

Итог: Этап compile в Maven — это комплексный процесс, который включает:

  1. Обработку ресурсов (filtering)
  2. Генерацию кода (из аннотаций, схем БД)
  3. Разрешение зависимостей (dependency resolution)
  4. Компиляцию Java кода с помощью javac
  5. Генерацию .class файлов в target/classes

Правильная конфигурация Maven compile обеспечивает корректную сборку, управление версиями зависимостей и оптимизацию времени компиляции.