Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUGNsk Meetup #3. Никита Липский: "Спасение от Jar Hell с помощью Jigsaw Layers"

jugnsk
August 23, 2018

JUGNsk Meetup #3. Никита Липский: "Спасение от Jar Hell с помощью Jigsaw Layers"

Модульную систему Java aka JPMS или Jigsaw часто критикуют из-за отсутствия версионирования, которое в других модульных системах призвано решать проблему Jar Hell. К счастью, в Jigsaw продумали способ борьбы с конфликтами при помощи так называемых слоев Jigsaw (Jigsaw Layers). В этом докладе мы разберемся, какие проблемы могли бы возникнуть, если бы в Jigsaw были явные версии для модулей, и как слои Jigsaw вместе с Jigsaw сервисами помогают решать проблему Jar Hell безопасно

jugnsk

August 23, 2018
Tweet

More Decks by jugnsk

Other Decks in Programming

Transcript

  1. Про себя ? •  Инициатор проекта Excelsior JET –  работал

    над проектом более 18 лет –  как идейный вдохновитель –  компиляторный инженер –  руководитель –  и много в каких еще ролях •  twitter: @pjBooms •  team blog: https://www.excelsiorjet.com/blog 3
  2. План доклада •  Очень краткое введение в Jigsaw •  Проблема

    Jar Hell •  Версионирование как способ решить Jar Hell •  Проблемы связанные с версионированием •  Jigsaw Layers •  Как решать Jar Hell с помощью Jigsaw Layers •  Демо 4
  3. Пример модуля // src/java.sql/module-info.java module java.sql { requires transitive java.logging;

    requires transitive java.xml; exports java.sql; exports javax.sql; exports javax.transaction.xa; uses java.sql.Driver; } 6
  4. Модульная система Jigsaw Jigsaw модуль •  импортирует: –  модули: requires

    –  сервисы: uses •  экспортирует: –  пакеты: exports –  сервисы: provides SomeService with ServiceImpl 7
  5. Модульная система Jigsaw 8 Module A Class A Module B

    Class B Module C Class C exports packageC; requires: A exports packageA; I requires A; requires C;
  6. Версионирование •  Для решения проблемы JAR hell в первых драфтах

    Jigsaw модуль мог иметь версию – соответственно импорт/экспорт квалифицировался версией – если два модуля требовали библиотеку разных версий, грузились обе версии библиотеки 16
  7. Версионирование Вопрос: Как реализовать версионирование? Задача: Имеем модуль A, использующий

    библиотеку Lib (v1), и модуль B, использующий Lib (v2). Требуется, чтобы обе версии Lib работали и не конфликтовали. Решение: грузить обе версии библиотеки разными загрузчиками классов. 19
  8. Версионирование Вопрос: Как реализовать версионирование? Задача: Имеем модуль A, использующий

    библиотеку Lib (v1), и модуль B, использующий Lib (v2). Требуется, чтобы обе версии Lib работали и не конфликтовали. Решение: грузить обе версии библиотеки разными загрузчиками классов. 20
  9. Версионирование Вопрос: Как реализовать версионирование? Задача: Имеем модуль A, использующий

    библиотеку Lib (v1), и модуль B, использующий Lib (v2). Требуется, чтобы обе версии Lib работали и не конфликтовали. Решение: грузить обе версии библиотеки разными загрузчиками классов. 21
  10. Версионирование •  ClassLoader образует уникальное пространство имен классов •  Если

    каждый модуль грузить своим загрузчиком классов, то нет конфликтов с классами других модулей 22
  11. Версионирование 23 com.foo App 1.0 com.foo parse-api 2.0 com.foo persist-api

    3.0 org.apache commons 2.1 org.apache commons 3.1 CL1 CL2 CL3 CL4 CL5 Разные версии apache commons могут одновременно жить в JVM
  12. Jigsaw и загрузчики Jigsaw – это не только модули, но

    и разбиение Java платформы на модули. 27
  13. Jigsaw и загрузчики Проблемы обратной совместимости: По спецификации getClassloader() ==

    null для всех классов платформы. Что противоречит разбиению платформы на модули, где каждый модуль грузится своим загрузчиком 28
  14. Jigsaw и загрузчики Проблемы обратной совместимости: По спецификации getClassloader() ==

    null для всех классов платформы. Что противоречит разбиению платформы на модули, где каждый модуль грузится своим загрузчиком 29
  15. Jigsaw и загрузчики Проблемы обратной совместимости: Даже то, что классы

    вашего предложения будут грузится многими загрузчиками может вызывать проблемы Ф 30
  16. Jigsaw и загрузчики Проблемы обратной совместимости: И даже то, что

    Application Classloader перестал наследовать URLClassloader уже вызывает проблемы Ф 31
  17. Версионирование? App 1.0 Foo 2.0 Bar 3.0 Baz 2.1 Baz

    3.1 A A Я - “A”! Нет, это я “A”! 41
  18. 43

  19. Loading constraints •  Loading constraints запрещают двум разным классам с

    одинаковыми именами (fully qualified) появиться в области видимости одного класса 44
  20. Loading constraints B.java: class B { T1 f1 = A.f;

    int f2 = A.m(t2); } A.java: class A { static T1 f; static int m(T2 t) Если B грузится загрузчиком L1, а A грузится L2, то JVM проверит, что (T1, L1) = (T1, L2) и (T2, L1) = (T2, L2) == 45
  21. Версионирование Еще деталь: импорт в ранних версиях Jigsaw специфицировался не

    просто версией, а диапазоном версий: –  Модуль мог декларировать, что может работать с зависимостями версий от и до 47
  22. Версионирование … после чего версионирование в модульной системе Java приказало

    долго жить. Нет версионирования – не нужны загрузчики классов для модулей. 51
  23. Jar Hell Stop! Но ведь в Jigsaw нет версий! У

    двух версий одной и той же библиотеки скорей всего есть одинаковые пакеты 55
  24. Jar Hell Stop! Но ведь в Jigsaw нет версий! У

    двух версий одной и той же библиотеки скорей всего есть одинаковые пакеты Jigsaw запрещает двум модулям иметь одинаковые пакеты (split packages) 56
  25. Jar Hell Но как же все таки решать проблему Jar

    Hell? App 1.0 Foo 2.0 Bar 3.0 Baz 2.1 Baz 3.1 57
  26. Jar Hell Другой вариант – разложить разные версии библиотеки по

    разным пакетам (Maven Shade плагин) Не всегда работает из-за reflection.
  27. Jigsaw Layers * Jigsaw layer: •  Локальная модульная система • 

    Внутри одного слоя запрещены split пакеты •  Разные модули с одинаковыми пакетами должны принадлежать разным слоям 63
  28. Jigsaw Layers * •  Слои Jigsaw реализованы …через загрузчики классов.

    •  У каждого слоя по крайней мере один свой загрузчик (может быть несколько) •  Но при этом невозможно по построению нарушение classloader constraints!
  29. Jigsaw Layers * •  Слои Jigsaw реализованы через загрузчики классов!

    •  У каждого слоя по крайней мере один свой загрузчик (может быть несколько) •  Но при этом невозможно по построению нарушение classloader constraints!
  30. Jigsaw Layers * •  Слои Jigsaw реализованы через загрузчики классов!

    •  У каждого слоя по крайней мере один свой загрузчик (может быть несколько) •  Но при этом невозможно по построению нарушение classloader constraints!
  31. Jigsaw Layers * •  Слои Jigsaw реализованы через загрузчики классов!

    •  У каждого слоя по крайней мере один свой загрузчик (может быть несколько) •  Но при этом невозможно по построению нарушение classloader constraints!
  32. Jigsaw Layers Jar Hell Resolution App 1.0 Library Foo 2.0

    Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 69
  33. Jigsaw Layers Jar Hell Resolution 70 App 1.0 Library Foo

    2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Boot Layer
  34. Jigsaw Layers Jar Hell Resolution 71 App 1.0 Library Foo

    2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer
  35. Layer 3 Jigsaw Layers Jar Hell Resolution 72 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer
  36. Jigsaw Layers Jar Hell Resolution App 1.0 Library Foo 2.0

    Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 73
  37. Layer 3 Jigsaw Layers Jar Hell Resolution 74 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer
  38. Layer 3 Jigsaw Layers Jar Hell Resolution 75 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer
  39. Jigsaw Layers •  У каждого слоя есть родительский слой • 

    Модули дочернего слоя могут импортировать модули родительского слоя •  Но модули родительского слоя не могут импортировать модули дочернего! •  Именно поэтому не возможны нарушения classloaders constraints!
  40. Jigsaw Layers •  У каждого слоя есть родительский слой • 

    Модули дочернего слоя могут импортировать модули родительского слоя •  Но модули родительского слоя не могут импортировать модули дочернего! •  Именно поэтому не возможны нарушения classloaders constraints!
  41. Jigsaw Layers •  У каждого слоя есть родительский слой • 

    Модули дочернего слоя могут импортировать модули родительского слоя •  Но модули родительского слоя не могут импортировать модули дочернего! •  Именно поэтому не возможны нарушения classloaders constraints!
  42. Jigsaw Layers •  У каждого слоя есть родительский слой • 

    Модули дочернего слоя могут импортировать модули родительского слоя •  Но модули родительского слоя не могут импортировать модули дочернего! •  Именно поэтому невозможны нарушения classloaders constraints!
  43. Layer 3 Jigsaw Layers Jar Hell Resolution 80 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer A A
  44. Layer 3 Jigsaw Layers Jar Hell Resolution 81 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 A A Boot Layer
  45. Layer 3 Jigsaw Layers Jar Hell Resolution 82 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 A A Boot Layer
  46. Layer 3 Jigsaw Layers Jar Hell Resolution 83 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 A A Boot Layer Я живу на одном Ну а ты на другом На высоком берегу на крутом
  47. Jigsaw Layers Вопрос: если модули основного приложения не могут импортировать

    модули дочерних слоев, как тогда использовать их функциональность?
  48. Jigsaw Layers Вопрос: если модули основного приложения не могут импортировать

    модули дочерних слоев, как тогда использовать их функциональность? Ответ: Использовать шаблон IoC через Jigsaw Services: cлои могут предоставлять сервисы в модули родительского слоя
  49. Jigsaw Layers Вопрос: если модули основного приложения не могут импортировать

    модули дочерних слоев, как тогда использовать их функциональность? Ответ: Использовать шаблон IoC через Jigsaw Services: cлои могут предоставлять сервисы в модули родительского слоя
  50. Jigsaw Layers Вопрос: если модули основного приложения не могут импортировать

    модули дочерних слоев, как тогда использовать их функциональность? Ответ: Использовать шаблон IoC через Jigsaw Services: cлои могут предоставлять сервисы в модули родительского слоя
  51. Layer 3 Jigsaw Layers Jar Hell Resolution 89 App 1.0

    Library Foo 2.0 Library Bar 3.0 Library Baz 2.1 Library Baz 3.1 Layer 2 Boot Layer
  52. Layer 3 Jigsaw Layers Jar Hell Resolution 90 App 1.0

    Foo 2.0 Bar 3.0 Baz 2.1 Baz 3.1 Layer 2 App Service Provider 1 App Service Provider 2 Boot Layer
  53. Как использовать var finder = ModuleFinder.of(Paths.get(“MyLayer”)); var parent = ModuleLayer.boot();

    Configuration cf = parent.configuration().resolve( finder, ModuleFinder.of(), Set.of(“myRootMod")); ModuleLayer myL = parent.defineModulesWithOneLoader( cf, ClassLoader.getSystemClassLoader());
  54. Как использовать var finder = ModuleFinder.of(Paths.get(“MyLayer”)); var parent = ModuleLayer.boot();

    Configuration cf = parent.configuration().resolve( finder, ModuleFinder.of(), Set.of(“myRootMod")); ModuleLayer myL = parent.defineModulesWithOneLoader( cf, ClassLoader.getSystemClassLoader());
  55. Как использовать var finder = ModuleFinder.of(Paths.get(“MyLayer”)); var parent = ModuleLayer.boot();

    Configuration cf = parent.configuration().resolve( finder, ModuleFinder.of(), Set.of(“myRootMod")); ModuleLayer myL = parent.defineModulesWithOneLoader( cf, ClassLoader.getSystemClassLoader());
  56. Как использовать var finder = ModuleFinder.of(Paths.get(“MyLayer”)); var parent = ModuleLayer.boot();

    Configuration cf = parent.configuration().resolve( finder, ModuleFinder.of(), Set.of(“myRootMod")); ModuleLayer myL = parent.defineModulesWithOneLoader( cf, ClassLoader.getSystemClassLoader());
  57. Как использовать var finder = ModuleFinder.of(Paths.get(“MyLayer”)); var parent = ModuleLayer.boot();

    Configuration cf = parent.configuration().resolve( finder, ModuleFinder.of(), Set.of(“myRootMod")); ModuleLayer myL = parent.defineModulesWithOneLoader( cf, ClassLoader.getSystemClassLoader()); var services = ServiceLoader.load(myL, MySrv.class);
  58. Где еще могут пригодиться слои Проблема: стандарт servlet контейнеров не

    знает пока про модули –  Зависимости в war файлах – это по сути тот же самый classpath! Решение: можно форкнуть ваш любимый app server, добавив модульный слой в его загрузчик приложений –  пример:
  59. Где еще могут пригодиться слои Проблема: стандарт servlet контейнеров не

    знает пока про модули –  Зависимости в war файлах – это по сути тот же самый classpath! Решение: можно форкнуть ваш любимый app server, добавив модульный слой в его загрузчик приложений –  пример: https://github.com/pjBooms/tomcat
  60. Заключение Версии для модулей кажутся хорошей идеей, но на деле

    с ними много проблем: – обратная совместимость – небезопасность (classloaders constraints) – NP-полнота на разрешение зависимостей
  61. Заключение Jigsaw Layers позволяют решать проблему Jar Hell безопасно: – невозможно

    нарушение classloaders constraints по построению – Jigsaw services помогают использовать функциональность реализованную в дочернем слое из родительского