Creating and importing a custom Spring library whilst separating shared dependencies

Robbo_UK :

Im looking to create a Spring library project to share across an internal team.

At a very basic concept level The library will send message events to a queue and my plan is to standardise this within a team across several Spring Boot Microservices send messages the same way.

My pom in the library project looks something like this

<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>

I have a service in the library project that looks like this

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;
  }
}

When I import the library into another project my thinking is that I can Autowire the EventService. By adding it in the pom and then @ComponentScan({"my.library.package.eventlibrary.service"})

How do I prevent spring version locking? If the library is using spring 2.1.5.RELEASE today and the project that imports the library uses a different version would I not end up with potentially maven conflicts?

Also lets say the project that imports the library uses a lower version of hibernate api and the library has 6.0.16.Final. How would I prevent the project from using the newer one found one in the library classpath?

To clarify my question further is there a way I can separate the dependencies in the library from the project that uses it.

Cepr0 :

You can try to exclude all transitive dependencies that your library can bring to projects that will use it.

To do this you should replace spring-boot-starter-parent with spring-boot-dependencies in dependencyManagement section and use provided scope for all dependencies which the library needs to work with and which will be exactly used by the projects, that will work with the library.

For example, a pom.xml of your library can be looks like this:

<!-- ... -->
    <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>
<!-- ... -->

Then you will be able to use your library in the different projects, that use for example the old 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>
<!-- ... -->    

So this project will use hibernate-validator:5.3.6.Final from its spring-boot-starter-web.

Important notes - the code of your library should be 'compatible' with this version of Spring Boot. In other words, you should test your library with different versions of Spring Boot in which you are interested.

See my project as an example.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=68691&siteId=1