Вступление

В 2024 году я начал изучать Spring AOP и решил проверять знания на практике - создал экспериментальный проект.

Идея была простой: что-то уникальное и реально полезное. На Java почти нет современных библиотек для интеграции с Python. Py4J и Jython либо ограничены, либо устарели, а полноценной интеграции с Spring Boot не было.

Так я решил создать библиотеку для связки Java и Python. Первоначально это был эксперимент с AOP и динамическим кодом, но в итоге проект вырос в полноценную open-source библиотеку, которую можно подключить одной зависимостью.

Начало эксперимента: изучение AOP в Spring Boot

Изначально проект под названием spring-python-executor позиционировался, как обычный пример моих навыков для резюме и ничего более. Поэтому к середине 2024 я быстро завершил разработку данного проекта. Он был написан на костылях, о какой либо безопасности или расширяемости в долгосрочной перспективе речи и не шло, но оно работало.

Первая версия проекта работала на шести аннотациях:

  • @PythonBeforeMethod

  • @PythonAfterMethod

  • @Py4JBeforeMethod

  • @Py4JAfterMethod

  • @SpelythonBeforeMethod

  • @SpelythonAfterMethod

@PythonBeforeMethod и @PythonAfterMethod работали с обычными скриптами, которые были независимы от Py4J или Spring Boot.
@Py4JBeforeMethod и @Py4JAfterMethod отвечали за использование Py4J вместе со скриптом указаным в методе.
@SpelythonBeforeMethod и @SpelythonAfterMethod были самым соком той версии. Эти две аннотации отвечали за Spelython или же по сути SpEL + Python. В каждом скрипте можно было использовать SpEL выражения.

И эту версию я решил выложить в Maven Central Repository по гайду на Ютубе, думая о том что эта версия проекта прокатит без должного тестирования.
P.S. Она не заработала, а забыл добавить spring.factories

Второй этап эксперимента: исправление и осознание

Вот мы и вернулись снова в 2025 и я решил полностью исправить своё резюме и проверить работоспособность моих проектов. Как вы уже догадались проект под названием spring-python-executor не оправдал ожиданий...

Я начал более углубленно изучать экосистему Spring Boot, а также как создавать свои Java проекты, которые не стыдно было бы разместить в Maven Central Repository.

После прочтения документации, я начал творить новое исправлять ошибки с прошлого. Ошибки в логике были максимально банальными и исправлялись в пару десяток минут, но глобальной проблемой было то, что проект было очень сложно расширять в случае нужды нового кода. А также исполнение скриптов через ProcessBuilder - не самый лучший вариант.

Поэтому осознав все проблемы я пришёл к выводу, что нужно делить этот массивный кусок спагетти-кода на разные модули и добавить больше возможностей к исполнению скриптов, например, через REST или gRPC.

Но перед этим я создал ещё поддержку RestrictedPython и понял, что 6 аннотаций избыточно и нужно менять контракты между интерфейсами.

Финальный этап эксперимента: переход к production-ready коду

Переименовав проект в 'spring-boot-python-executor' и разделив эти проекты на разный модули (spring-boot-python-executor-common, spring-boot-python-executor-core, spring-boot-python-autoconfigure, spring-boot-python-executor-starter), я улучшил качество кода и расширяемости во много раз. Теперь не было болью рефакторить большие куски кода.

Дальнейшим шагом был рефакторинг кода в каждом модуле. Первым делом я пофиксил все контракты между интерфейсами и создал централизированный PythonProcessor для исполнения Python скриптов и убрать избыточное количество аннотаций.

С этого момента имеются только четыре аннотации:

  • @PythonBefores

  • @PythonBefore

  • @PythonAfters

  • @PythonAfter

Аннотации с окончанием ...s служат для исполнения множества аннотаций без окончания, а также добавлено на этом этапе профилирование.

За Spelython или Py4J отвечает PythonResolverHolder, которые содержит список с PythonResolver с нужной реализацией.

За способ исполнения скриптов отвечает PythonExecutor, который с этим этапом приобрел две реализации: GrpcPythonExecutor и RestPythonExecutor. Также создано два сервера на Python, задеплоиные в Docker Registry Hub: w4t3rcs/spring-boot-python-executor-python-grpc-server, w4t3rcs/spring-boot-python-executor-python-rest-server.

Вишенкой на торте стало добавления модулей отвечающих за кэширование и реализацию testcontainers.

Со всеми этими правками, общее состояние кода намного улучшилось и скорость разработки увеличилась в разы.

Примеры использования

Ниже предоставляю самые базовые примеры библиотеки в действии.

1. Простые аннотации

@PythonBefore("print('Before')")
@PythonAfter("print('After')")
public void doSomething() {
    System.out.println("Hello from Java method");
}

2. Несколько скриптов (...s)

@PythonBefores({
    @PythonBefore("print('Before 1')"),
    @PythonBefore(script = "print('Before 2')", activeProfiles = "dev")
})
public void doSomething() {
        System.out.println("Hello from Java method");
}

3. С помощью PythonProcessor

@Service
@RequiredArgsConstructor
public class ExampleService {
    private final PythonProcessor processor;

    public String getResult(String script) {
        return processor.process(script, String.class).body();
    }
}

Для более внушительного ознакомления с данной библиотекой, я рекомендую прочитать README.md и Javadoc'и с репозитория проекта.

Заключение

За год путь моего небольшого эксперимента превратился в полноценный open-source проект с гибкой архитектурой, поддержкой REST, gRPC и безопасного исполнения Python-скриптов. Сейчас spring-boot-python-executor уже можно использовать в production, подключив всего одну зависимость.

Дальше я планирую расширять функционал, улучшать документацию, добавлять примеры реальных сценариев.

А теперь хочу спросить у вас:

  • Возвращались ли вы к своим незаконченным проектам с прошлого?

  • Приходилось ли вам интегрировать Python и Java в одном проекте?

  • Какой способ взаимодействия между ними для вас оказался самым удобным?

  • Интересна ли вам идея глубокой интеграции Python в экосистему Spring Boot?

Давайте обсудим это в комментариях! Буду рад обратной связи и вашим идеям по развитию проекта!

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


  1. PqDn
    18.08.2025 15:36

    Для питона как либы устанавливаются?


    1. w4t3rcs Автор
      18.08.2025 15:36

      Если через REST/gRPC сервер, то через PYTHON_ADDITIONAL_IMPORTS, если локально, то через pip. На гитхабе там полная инфа и о серверах и как их настраивать


  1. pkokoshnikov
    18.08.2025 15:36

    А graalpy чем не нравится? И причём тут spring? Кейсы применения непонятны. Такие аннотации обычно в коде руками реализовывают, если они действительно нужны.


    1. w4t3rcs Автор
      18.08.2025 15:36

      Я в ближайшее время хочу внедрить graalpy и jep в этот проект. А spring потому что все построено вокруг spring boot'a, тот же PythonProcessor это бин.