Подтвердить что ты не робот

Maven - отдельные модули для интерфейсов и реализации с Spring

Мы работаем над Mavenizing нашим проектом java, и мы хотели бы установить четкое разделение между интерфейсами и реализациями для каждого модуля. Для этого мы хотим разбить каждый модуль на два подмодуля, один для интерфейсов и объектов данных, используемых ими, а другой для реализации. Например:

 +commons 
  +commons-api 
  +commons-impl 

POMs модулей будут сконфигурированы таким образом, чтобы ни один модуль не зависел от подмодулей impl. Таким образом, ни один код из одного модуля не сможет "увидеть" детали реализации другого модуля.

С чем мы сталкиваемся, где разместить наши spring XML файлы. В нашем проекте мы автоматически импортируем XML файлы spring с помощью подстановочного импорта, например

<import resource="classpath*:**/*-beans.xml"/>

Таким образом, расположение XML файлов spring не имеет особого значения во время выполнения, так как все модули загружаются в один загрузчик классов, а строгие правила односторонней зависимости в POM не применяются.

Однако во время разработки мы хотим, чтобы IDE - мы использовали Intellij IDEA - для распознавания классов реализации, на которые ссылаются XML spring. Мы также хотим, чтобы IDEA распознавала beans, определенные в других модулях.

Если мы поместим XML файлы spring в подмодули API - они не будут "видеть" классы реализации в подмодулях impl. Если мы разместим их в подмодулях impl, их beans не будет "замечен" из других модулей. Вероятно, можно настроить проект IDEA на распознавание XML файлов spring из модулей, на которых нет зависимости, но мы предпочитаем, чтобы наши POM сохраняли всю информацию о структуре проекта и не полагались на файлы проекта IDEA.

Мы рассмотрели создание третьего подмодуля только для хранения XML файлов spring (и, возможно, спящего режима xmls). Например:

 +commons 
  +commons-api 
  +commons-impl 
  +commons-config

Внешние модули будут зависеть как от commons-api, так и commons-config и commons-config будут зависеть как от -api и commons-impl, при этом зависимость от commons-impl помечена как "предоставлена" (чтобы предотвратить переходное разрешение).

Это, однако, похоже на сложное и неудобное решение, и мы считаем, что должен быть лучший - более простой способ добиться разделения интерфейса/импликации с Maven и Spring.

4b9b3361

Ответ 1

Что вам нужно - это область зависимости времени выполнения:

runtime. Эта область показывает, что зависимость не требуется для компиляции, но предназначена для выполнения. Он находится в среде выполнения и тестирует пути к классам, но не компилирует путь к классам.

(https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)

Определите зависимость времени выполнения от одного модуля implim до другого модуля impl, где вы используете классы impl в конфигурации * - beans.xml. Intellij правильно распознает это в конфигурационных файлах spring, но не будет автоматически заполнять их в коде (но он будет делать это в тестовом коде).

Кроме того, если кто-либо использовал классы в коде, компиляция через maven завершилась неудачно, потому что зависимость времени выполнения не находится в пути класса компиляции.

Ответ 2

Вы можете добиться развязки api и impl следующим образом:

+ commons (pom)
  + pom.xml         <--- serves as a parent aggregator (see below)
  + commons-api (jar)  <--- contains models, interfaces and abstract classes only
  + commons-impl (jar)  <--- depends on commons-api
  + commons-config (jar) <--- depends on commons-impl only (no need to depend on commons-api as it is brought in transitively)

 + external-project (war or jar) <--- has commons-config as a dependency

Родительский агрегатор pom (укажите порядок сборки):

<modules>
  <module>commons-api</module>
  <module>commons-impl</module>
  <module>commons-config</module>
</modules>

Конфигурационный модуль можно опустить, если он содержит только конфигурацию контекста приложения spring. Конфигурация xml приложения должна находиться в структуре пути и структуре папок модуля, который содержит артефакт, который вы развертываете. Поэтому, если вы строите артефакт войны, там должен быть контекст приложения.

Единственная конфигурация, которая должна быть в вашем общедоступном модуле, будет в тестовом пакете вашего модуля impl.

Ответ 3

Короче говоря, вы хотите, чтобы Idea переопределил график зависимостей maven, но не сохраняйте эту конфигурацию в файлах проектных идей?

Один из вариантов - группировать зависимости реализации в профиле maven. Этот профиль не будет включен по умолчанию, но вы должны иметь возможность отмечать его как активный по идее.

Ответ 4

Приходят на ум две идеи:

  • У вас будет один (или более) модуль, в котором все модули (api + impl) будут зависимыми, вы можете разместить там конфигурационные файлы spring.
  • Поместите файлы конфигурации spring в модулях api и объявите зависимость от модуля impl с областью provided, таким образом, реализации будут известны, в то время как нет никакой зависимости от api для развертывания.

Ответ 5

  • commons-impl во время выполнения во внешних модулях

    • commons (pom dependencyManagement) = >

      + commons-api (компиляция)

      + commons-impl (компиляция)

      + commons-config (скомпилировать)

    • commons-impl (зависимости pom) = >

      + commons-api (компиляция)

      + commons-config (скомпилировать)

    • внешние модули (зависимости pom) = >

      + commons-impl (время выполнения)

      + commons-api (компиляция)

      + commons-config (скомпилировать)

Ответ 6

  • сохранить количество модулей как можно меньше;

    Это ускоряет время сборки проекта и упрощает его компоновку.

  • сохранить структуру модулей как можно более простой: один корень + все вспомогательные модули в той же папке, e. г:.

    pom.xml
    commons-api/
    commons-runtime/
    module-a-api/
    module-a-runtime/
    ... 
    

Это упрощает навигацию по проекту, когда число модулей действительно велико ( > 50)

  1. обеспечивают зависящие от времени исполнения зависимости от модулей времени выполнения только тогда, когда они требуются;

    Это упрощает вашу архитектуру. Используйте mocks вместо явной зависимости от другого модуля времени выполнения.

  2. сохраняйте контексты api spring в модулях api, определяйте свой общедоступный beans как абстрактный bean + интерфейс;

  3. сохраняйте контексты реализации в модулях времени выполнения, переопределяйте api beans с помощью ваших реализаций через профили spring (используйте < beans profile = "default" ).

Результат: простой, прозрачный макет и дизайн; полная поддержка идей; нет явных зависимостей от внутренних модулей встроенного программного обеспечения.