I'm creating a library having sub-modules for internal purposes. In one of those sub-module, I am using a spring based dependency. In order to allow the library's client using different spring versions to use the library, I was thinking to provide 2 different versions of the same code with different dependency version compiled (one for Spring 1 and another for Spring 2) and publish the same to mavenLocal.
What is the best way to achieve this (or is there a better way to achieve this for the clients) ? I don't want to maintain another module with same code and just a different dependency version.
Is it good to have different versions of a dependency in the same project that will be used for creating multiple artifacts?
If it is ok to do that, how do I create artifacts with different versions and publish them to mavenLocal corresponding to each versioned artifact? (if you can provide the gradle script it'll be really helpful)
I am new to using gradle and it'll be really helpful if someone can guide me for this problem.
Related
Experts,
I need some expert advice on how to approach the below use case in spring boot.
I need to have a maven multi-module approach to my project.
I need to have a single jar as output of the final build process.
There are to be common modules for controllers, data access and other functionality
Other modules are to be created based on functionality domain for eg a module for Payroll, a module for Admin etc etc.
Each domain functional module will then have their own controllers extending the common controller, exception handler and so on.
Each module will also have its own set of thyme leaf pages.
The reason for following such an approach is we have development in phases and we will be rolling out based on functional modules.
Here are the issues that I can sense using this approach.
Where do I add the spring web dependency? If I add to the parent pom - it gets replicated across the children and there will be port conflict issues as each module loads. the same issue will also be there the moment I add it to two child modules.
How do I build the fat jar which has all the jars from all modules and works as the final deployment?
All the text that I read i can't see anything even close to what I am trying to achieve.
AD1. They will not unless you are trying to setup independent application context in each module. Of course you can do that(it might be complicated but I believe it's achievable), but for me it's an overkill. Personally I think it's better to have one application context and rely on scanning components that are present in classpath.
AD2. The structure in maven might be a little bit complicated and overwhelming at first glance but it makes sense. Here's how I see it:
Create a parent module that will aggregate each module in project and will declare library/plugin dependencies for submodules.
Create 1-N shared submodules that will be used in other modules. With come common logic, utils, etc.
Create 1-N submodules that will be handling your business logic
Create an application submodule that creates application context and loads configuration and components from classpath
Create a submodule that will be responsible for packaging process, either to war, jar, uber-jar or whatever else you desire. Maven jar plugin should do that for you. For executable uber-jar, you have dedicated tool from spring.
Now you can choose three ways(these ways I know) of loading your modules.
1. Include some modules in maven build based on the build configuration via maven profiles and let spring IoC container load all the components he finds in the classpath
2. Include all of the modules in maven build and load them depending on spring active profiles - you can think about it as of feature flag. You annotate your components or configuration class with #Profile("XYZ") telling spring IoC container whether to instantiate component or not. You will need (most flexible solution) to provide a property file which tells spring which profiles are active and thus which modules should be loaded
3. Mix of these two above.
Solution 1 pros:
build is faster (modules that are not included will be skipped during build)
final build file is light (modules that are not included are... not included ;))
nobody can run module that is not present
Solution 1 contras:
project descriptor in maven may explode as you might have many different profiles
Solution 2 pros:
it's fairly easy and fun to maintain modules from code
less mess in project descriptor
Solution 2 contras:
somebody can run module that is not intended to be run as it's present in classpath, but just excluded during runtime via spring active profiles
final build file might be overweight - unused code is still present in code
build might take longer - unused code will be compiled
Summary:
It's not easy to build well structured project from scratch. It's much more easier to create a monolith and then split it into modules. It's because if you already created a project, you've probably already identified all the domains and relations between them.
Over past 8 years of using maven, I honestly and strongly recommend using gradle as it's far more flexible than maven. Maven is really great tool, but when it comes to weird customization it often fails as it's build capabilities rely on plugins. You can't write a piece of code on the fly to perform some custom build behaviour while buidling your project, you must have a dedicated plugin for doing that. If such plugin exists it's fine, if it's not you will probably end up writing your own and handling its shipment, so anyone in your company can easily perform project build.
I hope it helps. Have fun ;)
I want to reuse and centralize the utils I created for my Spring REST API for my future projects. That's why I thought I'd outsource them to my own project and make them available as a Maven dependency.
These Util files e.g. a basic service, basic controllers also contain Spring annotations, i.e. I need some Spring dependencies in my Util dependency. Now I'm a bit unsure whether I'm making a mistake or not.
First of all, I'm not sure if I should even use spring dependencies in a utility dependency or try to remove everything. Otherwise, I'll have to specify a spring version, but it might differ from the version I want to use later in the project it's included in. How am I supposed to solve this?
It is perfectly reasonable to have dependencies for your dependencies (these are called transitive dependencies). Of course, you should keep the number as low as possible, but on the other hand, you do not want to reinvent the wheel.
When somebody uses your dependency, they will automatically draw the transitive dependency on spring. Now, several cases can occur:
If this is the only reference to spring, the version is just used as you stated it.
If at some other point, a different version of spring is given, Maven dependency mediation kicks in. It decides by a "nearest is best" rule which version to take.
But: You can always set the spring version in <dependencyManagement> and then overwrite all transitively given version numbers.
That is the main concept of Maven. Your utility module must shipped together with Spring dependencies. It's called transitive dependencies.
Try to imagine that situation when all dependencies had excluded. In that case nobody will never know what kind and which version of Spring dependencies are needed.
Maven has a very good dependency conflict resolution. It's based on nearest-newest principle. So you can override those Spring versions easily and your application will use only one of that.
Take a look at these:
[1] Dependency Mechanism
[2] Dependency Mediation and Conflict Resolution
The problem I encountered is pretty standard: I need to have some common code base between micro-services despite the fact that this approach is discouraged as I've heard. At the moment I have common code as separate module that's built into jar and deployed to local Nexus. Then it's used as standard maven compile dependency. We use CI to build all modules. So when I want to change common code and use it in micro-service outright I can't do it. I must go through "two-stage process" when I first push common module changes, wait until module gets built and receives new version; and only then I can push micro-service code that uses that new version. That's at least awkward, in fact it's very annoying.
Can I use common module as some kind of "source dependency" in maven? What's the proper way to implement this?
The important question is: Is it ok for the different microservices to use different versions of the common jar?
If yes: You do not need to push changes. You update your common jar and test it separately (as far as possible). While updating a microservice, you can update the dependency (if you want). The microservices then run (possibly) different versions of your common jar.
If no: You can put your jar together with all microservices into one multi-module project, but this means that they all have to be built together every time. You cannot change and build a single one any more. But if they rely on common code in the very same version, they are tightly coupled, so that building only one is probably not a good idea anyway.
I'm currently maintaining a fork of the jodconverter project which offers a spring-boot-starter module, allowing a spring-boot based app to use an Open/Libre Office installation (on the same server) to automate document conversions.
Now, the project have grown and a new module was born, named jodconverter-online. This module will send conversion request to a LibreOffice Online server, and I now want to create a spring-boot starter to support this new module.
The current jodconverter-local (on which depends the current jodconverter-spring-boot-starter) does not have the same dependencies as the jodconverter-online module. This is why they are two separated modules in the first place.
So my question is:
Should I create a new jodconverter-online-spring-boot-starter or if it is possible (and how) to just modify the current starter project, making the dependencies optional according to the needs of the user.
For now I put it all in the current starter project (which is available as a 4.2.0-SNAPSHOT in the OSS snapshot repository), but I'm doing it the wrong way since it automatically adds the dependencies for both the jodconverter-local and the jodconverter-online modules.
You may want to make the dependencies to jodconverter-local and jodconverter-online optional, you just need to replace the keyword compile by compileOnly in your Gradle build file.
Obviously, when dependencies become optional, the developer will have to choose one of the options and add it to their project's dependencies (in addition to your starter).
If the only additional dependency is either jodconverter-local or jodconverter-online, that is no big deal. But if more dependencies have to be added for each case, then you might consider creating a new starter to encapsulate those dependencies.
As for the AutoConfigurations, I don't see any problem with what you did, since you use #ConditionalOnClass to trigger the AutoConfiguration only when the corresponding class is present on the classpath.
while working on spring mvc 4, how to find the jar for offline project like the jar Spring Security Config,spring-security-web for spring 4 ... etc as thet are not available with default package of jars and I do not want to use maven at this time so where one can find the jar for spring 4
?
First of all, foregoing proper dependency management is a bad idea and will make development that much harder, especially when it comes to transitive dependency resolving.
However, if you really want to do it then you can download .jars straight from Maven Repository or any other online repo that hosts them.
If that fails then a Google search will give you some source to download them from.
Trying to avoid a dependency management tool that to with a framework like Spring which complements many other frameworks is a bad idea in the long run. It will be painful to upgrade the versions in future.
But if you still don't want to use maven/gradle kind of build tool, just use pom.xml/build.gradle just for onetime use and let maven/gradle download all the dependencies and copy all those jars in some folder of your code.
Again I strongly suggest to use a build tool, especially for Spring. Maven/Gradle are not that bad if you don't want to do crazy things!!