Создание и импорт пользовательской библиотеки Spring с разделением общих зависимостей - PullRequest
5 голосов
/ 12 июня 2019

Я хочу создать проект библиотеки Spring, чтобы поделиться им с внутренней командой.

На базовом уровне концепции Библиотека будет отправлять события сообщений в очередь, и я планирую стандартизировать это в рамках группы по нескольким Spring Boot Microservices, отправляющих сообщения таким же образом.

Мой pom в проекте библиотеки выглядит примерно так

<artifactId>my-library</artifactId>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

etc...

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.16.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.2.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.6</version>
    </dependency>

У меня есть сервис в проекте библиотеки, который выглядит так

public class EventService {

  Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

  public void sendAuditEvent(AuditMessage auditMessage){

    Set<ConstraintViolation<AuditMessage>> violations = validator.validate(auditMessage);

    if(!isEmpty(violations)){
      log.error("Unable to send audit message");
      violations.stream().forEach( v-> log.error(v.getMessage()));
    }
    log.info("Found {} violations", violations.size());
    // etc blah blah
    return;
  }
}

Когда я импортирую библиотеку в другой проект, я думаю, что могу автоматически связать EventService. Добавив его в пом, а затем @ComponentScan({"my.library.package.eventlibrary.service"})

Как предотвратить блокировку пружинной версии? Если библиотека сегодня использует spring 2.1.5.RELEASE, а проект, который импортирует библиотеку, использует другую версию, разве я не столкнусь с потенциально опасными конфликтами?

Также допустим, что проект, который импортирует библиотеку, использует более низкую версию hibernate api, а библиотека имеет 6.0.16.Final. Как бы я не позволил проекту использовать более новый, найденный в пути к классам библиотеки?

Чтобы прояснить мой вопрос, есть ли способ отделить зависимости в библиотеке от проекта, который ее использует.

Ответы [ 3 ]

3 голосов
/ 15 июня 2019

Pre Java 9. Вы можете исключить зависимости Spring, используя maven, когда объявляете зависимость от вашего модуля, то же самое происходит и в Hibernate. Но вы не можете сказать своему модулю использовать другую версию hibernate в WAR.

Если вы хотите обойти это, вы можете разработать свою библиотеку как независимый интерфейс предоставления микро-услуг в форме REST или Websocket, если вы хотите полнодуплексную связь или что-то еще JMS, что угодно ....

После Java 9 вы можете использовать модульность java для определения точных зависимостей для вашего jar-модуля. Проверьте проект Jigsaw https://www.baeldung.com/project-jigsaw-java-modularity.

В вашем случае, чтобы иметь разные версии одной и той же библиотеки (hibernate). Вам понадобятся два отдельных загрузчика классов. Для этого вам нужно использовать многоуровневую систему, читайте здесь http://openjdk.java.net/projects/jigsaw/spec/sotms/#layers

А вот исходный код многих примеров, в том числе с использованием слоев. Сосредоточьтесь на них: https://github.com/accso/java9-jigsaw-examples/tree/master/jigsaw-examples

2 голосов
/ 16 июня 2019

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

Для этого вам следует заменить spring-boot-starter-parent на spring-boot-dependencies in dependencyManagement section и используйте область действия provided для всех зависимостей, с которыми библиотека должна работать и которые будут точно использоваться проектами, которые будут работать с библиотекой.

Например, apom.xml вашей библиотеки может выглядеть следующим образом:

<!-- ... -->
    <groupId>com.example</groupId>
    <artifactId>library</artifactId>
    <version>0.1.0</version>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <spring-boot.version>2.1.5.RELEASE</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
<!-- ... -->

Тогда вы сможете использовать свою библиотеку в различных проектах, которые используют, например, старый Spring Boot:

<!-- ... -->
    <groupId>com.example</groupId>
    <artifactId>old-project</artifactId>
    <version>0.13.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.19.RELEASE</version>
        <relativePath/>
    </parent>
<!-- ... -->
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>library</artifactId>
            <version>0.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
<!-- ... -->    

Таким образом, этот проект будет использовать hibernate-validator:5.3.6.Final из его spring-boot-starter-web.

Важные примечания - код вашей библиотеки должен быть «совместим» с этой версией Spring Boot.Другими словами, вы должны протестировать свою библиотеку с различными версиями Spring Boot, которые вас интересуют.

См. Мой проект в качестве примера.

0 голосов
/ 19 июня 2019

Возможно, это не то, что вы ищете, но вы можете распространять свою библиотеку как модуль автоматической настройки spring-boot-starter (конечно, если клиенты являются приложениями с весенней загрузкой).

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

В вашем конкретном случае, если вам нужно обязательно отправить сообщение в очередь, вы обязательнонеобходимо иметь соответствующие классы в classpath.С автоматической настройкой вы можете иметь Условия класса или Been Условия , в зависимости от которых вы можете отслеживать, имеют ли ваши клиенты правильные конфигурации во время выполнения.Вы также можете потерпеть неудачу при загрузке контекста, если что-то не так (предоставив значимое сообщение об ошибке).

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

...