Pull to refresh
25
0

Пользователь

Send message

Как ускорить Maven сборку без переезда на Gradle

Level of difficultyMedium
Reading time12 min
Views3.2K

С ростом размера Maven проекта встает вопрос скорости сборки и выполнения тестов. Один из самых очевидных способов оптимизации - переезд на другую систему сборки (например, Gradle). Однако перед тем как переезжать (что неизбежно создаст новые проблемы - об этом в конце) давайте поговорим о том, что мы можем сделать для ускорения, оставаясь на Maven. Тем более что многие советы нам пригодятся в любом случае, даже если переезд в итоге и состоится.

Мы начнем с простого, поговорим про кеши и build-сканы и затем заглянем под капот Maven, чтобы понять, как найти и устранить узкие места, а также детально сравним с Gradle. Эффект от каждого совета по отдельности может быть и не такой заметный, но в совокупности ускорение может быть в разы!

В рамках этой статьи мы поговорим в основном про оптимизацию компиляции.

Погнали

Получение generic-типа в runtime

Reading time5 min
Views16K


В Java 5 появились generic-типы, а вместе с ним и концепция type erasure, которая буквально означает стирание информации о generic-типе после компиляции. Действительно, во многих случаях это просто синтаксический сахар, помогающий писать типо-безопасный код на уровне компиляции, и в runtime с такими типами работать нельзя. Например, невозможно получить тип T внутри ArrayList<T>, поэтому он в своей реализации создает массив Object[], а не T[] для хранения элементов.

Однако, в ряде случаев это очень даже возможно. Например, можно объявить поле

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
...
@Autowired
private Set<BeanPostProcessor> beanPostProcessors;

и spring в него заинжектит все объекты контекста, которые реализуют интерфейс BeanPostProcessor.

Можно написать и так:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
...
List<String> strings = new ObjectMapper()
     .readValue("[1, 2, 3]", new TypeReference<>() {});
// все элементы strings - строки (не Integer и не Long)
List<Integer> ints = new ObjectMapper()
     .readValue("[1, 2, 3]", new TypeReference<>() {});
// все элементы ints - Integer (не String и не Long)

Можно написать даже так:
Читать дальше →

Методы расширения в Java

Reading time3 min
Views18K


В таких языках программирования, как C#, Kotlin, Groovy, Scala есть возможность расширять класс путем добавления нового функционала, при этом не требуется наследование или изменение самого изначального класса. Это реализовано с помощью специальных выражений, называемых расширения. Java, в отличие от этих языков, не имеет такой возможности из коробки и даже не планирует в ближайших релизах. Благодаря Lombok это стало возможным. Методы расширения были реализованы в Lombok еще 8 лет назад (с поддержкой Eclipse), но для многих все упиралось в поддержку плагином в IDEA (код компилировался, но IDE его не распознавала как валидный). Lombok плагин теперь предустановлен в IDEA 2021.1 EAP, и теперь он поддерживает методы расширения lombok (спасибо Anna Kozlova, Tagir Valeev, NekoCaffeine и Michail Plushnikov).
Рассмотрим пример классического статического импорта:


import static org.apache.commons.lang3.StringUtils.capitalize;

public class ExtensionMethods {
    public static void main(String[] args) {
        String str = "test";
        String capitalized = capitalize(str);
        // "Test"
        System.out.println(capitalized);
    }
}

при переходе на метод расширения код станет выглядеть так:


import lombok.experimental.ExtensionMethod;
import org.apache.commons.lang3.StringUtils;

@ExtensionMethod(StringUtils.class)
public class ExtensionMethods {
    public static void main(String[] args) {
        String str = "test";
        String capitalized = str.capitalize();
        // "Test"
        System.out.println(capitalized);
    }
}
Читать дальше →

Получение Method из Method Reference в Java

Reading time6 min
Views8.1K

Я столкнулся с проблемой — как получить из method reference вида


Function<String, Integer> fun = String::length;

вызываемый метод класса (или хотя бы его имя), т.е. в примере это java.lang.String.length(). Как выяснилось, не одного меня волновал этот вопрос, нашлись такие обсуждения на stackoverflow [1], [2], проекты на GitHub, которые так или иначе касаются этой проблемы [1], [2], [3], но не один из них не дает ровно то, что нужно. На Хабре ibessonov предложил свое решение, а apangin — свое в комментарии. Вариант Андрея мне понравился, но вскоре выяснились некоторые связанные с ним проблемы. Во-первых, это основано на внутренних классах JDK, все это работает только в Java 8, но не в более поздних версиях. Во-вторых, этот метод имеет ряд ограничений, например для BiFunction или BiConsumer он выдает неверное значение (это как раз обсуждается в комментариях).


В общем, перебрав несколько вариантов, удалось найти тот, который не имеет этих изьянов и работает в поздних версиях JDK — SerializedLambda. Забегая вперед сразу скажу, что это работает только с функциональными интерфейсами, помеченными как java.io.Serializable (т.е. с java.util.function.Function работать не будет), но в целом это не проблемное ограничение.

Читать дальше →

Магия CharSequence

Reading time5 min
Views39K
java.lang.CharSequence только на первый взгляд кажется незатейливым интерфейсом из трех методов, но при детальном рассмотрении открывает нам несколько интересных нюансов.
Интерфейс реализуют такие java-классы как String, StringBuffer, StringBuilder, GString (groovy) и не только.

TL;DR если добавить этот интерфейс в класс, он получит часть свойств строки и появится ряд возможностей — сравнения со строками (например, String.contentEquals), использования различных строковых API (например, Pattern.matcher), а также в местах автоматического определения поведения в зависимости от типа (например, биндинг параметров запроса в jdbc).

Кроме того, этот подход упростит проведение ряда рефакторингов по усилению системы типов в приложении — в первую очередь замены объектов типа String на специализированные обертки или enum-константы.

Строковые скаляры


Для добавления ограничений на формат значения, а также усиления type safety, вместо строк могут использоваться специальные скалярные обертки. Для понимания рассмотрим пример — пусть ID клиента является строкой, соответствующей регулярному выражению. Его класс-обертка будет выглядеть примерно так:
Читать дальше →

Перевод legacy-проекта на Dependency Injection. Путь Ситха

Reading time8 min
Views14K
Внесу и свой вклад в тренд темного программирования.
Многим из вас знакома дилемма: использовать ли DI в своем проекте или нет.
Поводы перехода на DI:
  • создание развитой системы авто-тестов
  • повторное использование кода в различном окружении, в том числе в различных проектах
  • использование 3rd-party библиотек, построенных на DI
  • изучение DI
Доводы не использовать DI:
  • усложнение понимания кода (поначалу)
  • необходимость конфигурирования контекста
  • изучение DI

Допустим, у нас есть большой рабочий проект, принято решение: переводить на DI. Разработчики чувствуют свой потенциал, уровень мидихлориан в крови зашкаливает.

Путь тебя ждет тернистый и долгий, мой юный падаван.

Если проект большой и в нем много разработчиков, одним коммитом вряд ли удастся сделать такой рефакторинг. Поэтому мы используем несколько плохих практик, упростив переход, а затем от них избавимся.
С чего начать?

Простой релиз-менеджмент средствами Git

Reading time2 min
Views32K
image
Git – это не только удобная распределенная VCS, но и инструмент подготовки релизов.
В статье будет рассмотрен flow на примере Java-проектов на Maven. Статья может быть полезна для разработчиков малых и средних команд, подразумеваются базовые знания git. Материал частично перекликается с git-flow, но здесь описан более простой вариант.
В классическом случае в репозитории существует одна ветка master, из нее же делаются сборки. Если проект собирается при этом на build-сервере, это может привести к беспорядку – несколько разных билдов под одной версией, не ясен набор коммитов, которые попадают в релиз (например, если сборка делается автоматически по триггеру на VCS).

Читать дальше →

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer, Build tool engineer