Java – How to Split a Big Project into a Multi-Module Maven Project

Architecturedesignjavamavenweb-development

I am working on a Spring-MVC application in which we are using Maven for dependency management. As the project is big, we are thinking of splitting the project into several parts. I had some doubts, which I hopefully will get answers here.

Currently, we are deploying a single WAR file as ROOT.war on Apache tomcat on our server. As the project is big, there are parts in the webapp like Notifications and Email, Third party services, PUSH (Cometd),REST API's, etc. Currently all of them are clubbed and are dependent on each other. For example, Notification object also depends on Person object, as Notifications are tailored for users.

The main intention of splitting the big project is to be able to work on individual modules, for bug fixes, adding features, testing, etc. And when satisfied, then only this module can be replaced on the server instead of the entire application. Is this possible?

As I already mentioned before, there are dependencies and mappings between objects. How will those be managed across different sub-modules, or will just the import statements change to include other projects?

As I said, the intention is to work on individual modules and be able to deploy them(preferably hot). Currently, we have only a single WAR file as ROOT.war. Will splitting create multiple war files, which are then referred by URL as domain-name.com/module_name/some_mapping?

I am currently checking the documentation, but this is the primary objective we want to achieve with multi module provided by Maven and interested to know if this is feasible. If there is any more information required, please let me know.

Currently I am using a parent POM from spring as follows:

<parent>
    <groupId>io.spring.platform</groupId>
    <artifactId>platform-bom</artifactId>
    <version>1.1.3.RELEASE</version>
    <relativePath />
</parent>

Best Answer

Is it possible?

Yes certainly. I have, in the past, structured a few projects like this. Here are some bits I hope will get you started.

There are two main features of Maven you will use to weave things together:

Divide and conquer

You will need to split your projects into multiple independent ones. Here, by independent, I mean that all references to code outside the project is done through dependencies in Maven and not directly merging the source tree.

Depending on the state of your source tree, this could represent a lot of work. That said, you are not doing it to shoehorn to Maven, but rather as a means to structure and sanitize your code base. Think of it as your toolshed, much easier to find things here:

Nice toolshed

than here:

Not-so-nice toolshed

Maven relies heavily on convention, so the better organized your stuff is, the more Maven can help you. That said, it may require you to re-organize to better fit its own convention, and if I have to give one piece of advice here, it's that it's MUCH easier to change your stuff to fit Maven's conventions than it is to try and configure Maven to understand your convention.

If these projects could be usable outside the main application, they could live as truly independent libraries and included through maven dependencies. They should live in their own repository (not in the application source tree) and should not depend on any part of the main application.

Core parts of your application, once split into projects, can be put together as modules. Typically, you will have them placed as sub-folder of the main source folder of your app.

Also, your parent POM for your app will contain the module declaration. You will also place in there all the common dependencies for your app as well as declare most of the build plugins and their configuration. In here also, I strongly recommend you place a group of properties for things such as the version of the application which you can reuse in the modules. Much easier to manage when everything have the same version and having the version in one place makes this just work.

Tooling

If you are a team larger than one, I would also strongly recommend that you install a repository for your Maven dependencies. Look at Artifactory, Nexus or Archiva. You can configure the POM file to install to these directly so once running it should not be much of an overhead but will save your team a lot of time resolving the dependencies with the correct jar in the correct place.

On the subject of tooling, the next logical step here is a continuous integration system (Jenkins, there are many more). It will handle building the source, running the tests, and pushing to the artifactory. With all this in place, all you have to do is work the code and the rest just works.

Since you are packaging your app as a war, maven can handle building the war and place all the dependencies in their proper places without having to merge jar files or other similar work around, so no worries there.

Example

I could go on much longer here, but nothing beats a good example. Look on GitHub for projects of similar magnitude and see how they built their pom files and folder hierarchies. Look at more than one, some will fit your setup better than others. None really incarnate the truth, but you should find enough to fuel your thoughts on how to get it done.

Take Jenkins for example:

You can see their parent POM is quite extensive.

They do use modules as you can see in this section:

<modules>
    <module>core</module>
    <module>war</module>
    <module>test</module>
    <module>cli</module>
</modules>

And each module correspond to a sub-folder with the same name that also contains a POM. You could nest as many as you want like this, though do keep it within sanity levels ;).

Start Small

If you have never used Maven, I would suggest, however, you do not start with modules right away. Take it slow, start with, say, one of the simpler libraries you may have and make it a maven project. Then make your main application a simple maven project. Once that work, start adding simple dependencies, then split your first module and so on.

Maven is a great tool, but it can also be a super pain in the neck, especially when things are not going your way. Starting with the whole whammy on your first go is a recipe for disaster (was for me!).

If things are a bit weird, you can always use mvn help:effective-pom command to see what Maven actually understood.

Plugins

From your comment, I understand better what you want to achieve. In this case, I would go for plugins approach. Create a project that exposes the API of extension points where you want to isolate the work. Then you can use this as a dependency in a new project that will implement it. In your main application, just add the proper dependencies for these implementations (not using maven modules this time) and you should be good to go. Eventually, the main application project will carry nearly no source code, everything being done in external projects and loaded through dependencies.

You will need to re-deploy the whole application however with this approach, regardless if the core changed or not as the war is statically built from the dependencies, changing one of them implies rebuilding the whole thing. It sounds worst than it actually is. In effect, only the new changes will actually get built, the rest will basically be a copy of the previous jar(s). But since everything is in the war file, it will need to be re-built, and the server will need to be stopped and restarted.

If you need to go further, things get a tad bit more complicated, though not impossible. I would recommend you look into OSGI, Apache Felix could get you started, though there are other implementations as well. This will allow you to take the external jar and make them into proper plugins. You will gain a lot more control on the runtime lifecycle of the components, opening the door to dynamic reloads and updates. It will, however, require major changes to your core, so again, probably not a good starting point. However, once you have a project that is well separated and have all the parts isolated the way you want, that could be a natural next step if starting and stopping the application on update is a major problem.

The basic difference between Modules and dependencies is this:

  • Modules will live in the same source tree as the main application, as sub-folders ideally.
  • Dependencies can be anywhere.

You can find the bible here.

Hope this helps, good luck.