简体   繁体   中英

Maven Java interface and implementation multi-module issue

Let's say I have a re-use project with 2 modules: api and service. The re-use api module defines interfaces, types, annotations that can be used by other application projects. The re-use service module contains the real implementation. The re-use project looks like this:

pom.xml: id=reuse, group=com.test.project, version=1.0.0
|__api-module
        |__pom.xml: parent={id=reuse, group=com.test.project, version=1.0.0}, id=reuse-api
|__service-module
        |__pom.xml: parent={id=reuse, group=com.test.project, version=1.0.0}, id=reuse-srv

And one of our applications has a depdency to the re-use module.

pom.xml: id=application, group=com.test.project, version=2.0.0
         dependency={scope=compile, id=reuse-api, group=com.test.project, version=1.0.0}
         dependency={scope=runtime, id=reuse-srv, group=com.test.project, version=1.0.0}

The thing is, if now we change something in the re-use service module, meaning we change the implimentation of the re-use module, the whole re-use module(api and service) has to be compiled and a new version will be released, because the versions of the api and the service module inherict from the parent module. The new pom structure will look like this:

pom.xml: id=reuse, group=com.test.project, version=1.0.1
|__api-module
        |__pom.xml: parent={id=reuse, group=com.test.project, version=1.0.1}, id=reuse-api
|__service-module
        |__pom.xml: parent={id=reuse, group=com.test.project, version=1.0.1}, id=reuse-srv

After that, the application has to change the dependency with the new version of re-use:

pom.xml: id=application, group=com.test.project, version=2.0.1
         dependency={scope=compile, id=reuse-api, group=com.test.project, version=1.0.1}
         dependency={scope=runtime, id=reuse-srv, group=com.test.project, version=1.0.1}

Is there a way that the modification of re-use service module will not cause a change also to the application? The application does not really need to be affected by the change of the re-use implementation or?

Do you have some comments/suggestions? Thank you.

Lets assume that you have your 2 modules stored in some artifact repository (for example some repository manager hosted in your company)

service-api-1.0.0
service-impl-1.0.0

There modules are shared across several applications:

app-1
   compile: service-api-1.0.0
   runtime: service-impl-1.0.0
app-2
   compile: service-api-1.0.0
   runtime: service-impl-1.0.0

The applications should define your repository in build configuration ( additional maven repository ) and reference them by version number.

Every time you complete a set of changes on your API/implementation you should release a library with a higher version.

Library version usually consist out of 3 components [major].[minor].[bugfix]

  • Bugfix version should be updated each release when there are no new features but just fixes to existing functionality.
  • Minor version is updated when there are new features that are backward compatible with the previous release.
  • Major version is changed when we introduce incompatible changes.

Eg when fixing some implementation defects in service-impl-1.0.0 you are releasing service-impl-1.0.1 . This one may/should be still compiled against service-api-1.0.0 .

This new version will be installed in your repository, then its contents will be

service-api-1.0.0
service-impl-1.0.0
service-impl-1.0.1

Unless you update the configuration of your application it will still be compiled and build against the older version still available in your repository. So you can have now:

app-1
   compile: service-api-1.0.0
   runtime: service-impl-1.0.0
app-2
   compile: service-api-1.0.0
   runtime: service-impl-1.0.1

There is no need to change each application as long as they have access to historical versions of your library. You change the dependency version only when you want to get new features in (very much the same way you do about any other public shared library in maven central).

If you change the code of your library, the application has three choices:

  1. Use the new version and compile again.
  2. Stay with the old version and ignore the changes made.
  3. Do not compile again but use the new library at runtime.

The third option is a bit risky because it requires all interfaces and all behaviour to be unchanged, otherwise you might get runtime exceptions. It is pretty common, though.

If you really want to decouple the implementation of the library from the application, you need a different kind of dependency, eg a REST service. In the effect, this is similar to (3) because you change the implementation of the REST service but guarantee that the behaviour and interface is unchanged.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM