There are many Maven artifacts named spring-boot-starter-*. As the names imply, they are very useful for an application project to get started with Spring Boot.
However, after the application project become stable, should it keep using these spring-boot-starter-*?
My concern is that doing so uses the Maven mechanism of "transitive dependencies", and it seems to violate the suggestion in Maven documentation:
Although transitive dependencies can implicitly include desired dependencies, it is a good practice to explicitly specify the dependencies you are directly using in your own source code.
For example, suppose an application project directly uses the Spring annotation #EventListener. The annotation is in the Maven artifact spring-context, and spring-context is included in spring-boot-starter. Should the application project directly specify the dependency on spring-context after it become stable?
The Spring Boot starter artifacts are just a shorthand for including several Spring Boot artifacts at once. My company has services in production that use starter artifacts. Of course, you could replace each starter with a list of the artifacts it contains, but I think the Maven suggestion is more about unrelated transitive dependencies, such as if your application inherited Guava from some JSON library as a transitive dependency.
When the transitive dependencies all come from the same source and are designed to work together, I don't think it's a problem. At least, I don't see it as such.
Related
I'm working on a project with a library module that has about 10 submodules.
For the application project the developer asked us to find a way so that they can import only one dependency, instead of the requested 10. Let's use as an example the dependency of log4j: I need only to include one not all the sub-dependencies.
How can I achieve this kind of structure for my library?
I believe this can be accomplished by making use of Maven's transitive dependencies. Essentially, you will create a new project which then has dependencies on all the other dependencies you want to group and provide to another application. You can then add the new project as a dependency in the application's POM, bringing in all the transitive dependencies.
This is kind of similar to the Spring Boot Starter dependencies, which package a few Spring dependencies together to make it quick to get started with Spring Boot. See https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-starters/spring-boot-starter/build.gradle
I am using spring-retry in my spring-boot service, as well as spring-boot library.
I Noticed this scenario to work:
Use spring retry logic in the library, but the spring retry jars are not imported in the library
Use the library in the parent service as a maven dependency.
The parent service imports spring-retry maven jars.
Is is normal for the library code to use the maven jars from the parent app ? and not need to import the jars itself ? My common intuition says it should, as the resulting compilation unit will have the dependencies injected.. but not sure.
Sorry if this is a super naive question, but my searches did not give a good answer (maybe want using the right keywords)
I'm not sure I've got you right, probably this question should be rephrased.
So you say, that there is a "spring-boot library" that uses spring retry logic.
If so, this library has a maven module and it gets compiled into a regular jar, right?
But if so, if it uses classes/interfaces/annotations from spring retry library and doesn't have it on the compile class path how it gets compiled? I believe you do have this spring retry library in the dependencies but just don't notice (try mvn dependency:tree in the spring boot library module to see the dependencies)
Other than that - usually when you develop a library its intended to be reused by different applications, and if it has dependencies on its own, usually it should list them in the project's library pom. Also usually people who develop the library try to minimize the dependencies list of the library itself.
So if pom.xml of the library doesn't list the required dependencies it won't even compile.
Now in runtime, all the dependencies (including transitive of course) should be available to the spring boot application, otherwise the class that uses these dependencies might not load. But other than that, spring, being a runtime framework, doesn't really care how did the dependency find its way into BOOT-INF/lib folder - its expected to work as long as the dependency is there.
Here is the simple situation breakdown and I'd like to know if I'm doing this optimally or if there is a better convention. I have created a dummy project just for learning purposes.
I have created a multi module Maven project. Simply the parent POM, with two sibling child POMS, one being a service layer, and the other being a web layer.
The end result goal is to have a fully functioning WAR in the Web project's target folder, that I can simply deploy into a Tomcat.
Here is where I am not clear:
- Both the Service project, and the Web project need to use Spring. The Service project needs to use Spring simply for it's dependency injection purpose. I need to take a simple Dog class, and auto-inject it into the DogService object. That's all working fine.
- Then I need to auto-inject a DogService object into a Dog controller. The Dog controller exists within the Web project in the multi module structure. This is also working fine, because I have declared a dependency in the Web project for the Service project, therefore all Service JARs are included in the final built WAR, from the web project.
1) Is there a way to simply declare a Spring dependency for both child projects without having to declare the dependencies in each child POM.xml? I just want to make sure I'm not duplicating resources. I believe the way to do this is just to declare the dependency in the Parent POM.xml.
2) If I do #1 above ^, is this the optimal way of creating the project? In essence, the WEB module is the one that contains all the final jars, and in essence it's almost as if the SERVICE project doesn't even exist in Tomcat. As far as Tomcat 'knows', all there is, is a bunch of JAR files containing classes, some of them having been written in my WEB module, and some of them having been written in the SERVICE module, all of which is irrelevant to the production/Tomcat environment. True or false?
Thanks!
Is there a way to simply declare a Spring dependency for both child projects without having to declare the dependencies in each child POM.xml? I just want to make sure I'm not duplicating resources. I believe the way to do this is just to declare the dependency in the Parent POM.xml.
Maven is quite intelligent about dependency management and will not "duplicate" resources--it caches each dependency once* and manages the classpath so that all of the projects that you work with share the same jars. In general, declare dependencies in the modules where they're needed; don't clutter up modules or especially parents with random pieces just to avoid occasionally re-specifying a dependency. This is like hauling your boat trailer on your daily commute because you occasionally go to the lake.
Keep in mind that dependencies are transitive, so that if service-module depends on spring-web (does it really, or are you spamming dependencies?), if web-module depends on service-module it will pull in the dependency as well without having to repeat yourself.
If I do #1 above ^, is this the optimal way of creating the project?
No, it isn't. Be minimalist about your dependencies: If you need it, include it, but don't add dependencies "defensively". This will just bloat your deployment and slow down builds, along with adding opportunities for problems like version mismatches.
As far as Tomcat 'knows', all there is, is a bunch of JAR files containing classes, some of them having been written in my WEB module, and some of them having been written in the SERVICE module, all of which is irrelevant to the production/Tomcat environment. True or false?
Mostly false. In a war, your top-level project (web-module) has its classes directly in the archive, and dependencies are embedded as jar file inside it. Tomcat does not distinguish between service-module and your Spring and other dependencies, however.
Better still would be using Spring Boot's standalone jar and embedded container features--Boot will take care of packaging up the jars you need into a single runnable file that doesn't need external support.
*Release dependencies only, but snapshots aren't relevant here.
I have a project based on Spring which is running successfully. Now I have created another project based on Jersey which I want to integrate with spring project in Jersey.
I have gone through internet and I added spring project in the build-path of the Jersey project.
Here the problem is whenever I run my Jersey project, it has to execute the Spring project first.
How to configure spring project in Jersey?
You should consider using a dependency management/build tool such as Maven or Gradle.
This way each of your projects will be a module, which can be referenced from the other project as a dependency. You can still use the first project alone and the two-dependent projects alone as wall. Then the tool lets you just simply package the resulting project in a artifact such as WAR with all the dependencies.
Here is a quick maven tutorial - Maven in 5 Minutes
It is a good idea to use such a tool in any case as it has many additional advantages:
Lets you manage also your third party dependencies without needing to manually download the libraries and add them to the classpath
It is much easier to use such a project in cases like continuous integration.
You can run all your tests automatically during the build process to make sure everything works
It resolves transitive dependencies (dependencies of your dependencies)
It builds resulting archive file for you
You can have multiple profiles for different environments
...
Make both of your projects modules of one Maven parent pom project. This way you can build them both at the same time.
With maven we can exclude some transitive dependencies.
But what if we need them at runtime, and still as architect I don't want them to be used and become API dependencies.
Is there tool to define and check for unwanted used dependency (i.e. imported in some Java class)?
A search here gives me hint for maven
In maven, can you disallow usage of transitive dependency in your code but still keep it in the classpath?
But that may be to laborious to define. Maybe IDE tools should be used?
How to disallow import and use of some transitive maven dependencies?
So that code will not be accessing different layers of our stack.
Yes, I understand that some educational work should go as well.
When dealing with maven there is a concept of dependency scope. Typically for Java EE applications you will see 3 scopes leveraged the most:
Compile - This is the default scope used if none is specified. These will be available in all of a project's classpaths.
Provided - This scope is used when the dependency is not needed for compilation, but is expected to be in the container at runtime.
Test - This is a dependency needed for testing, but not required for the normal use of the application
Based off of your use case I believe you are looking to leverage the provided scope for a dependency where the dependency is needed at runtime, but should not be available to the application during compilation. You can read more about dependency scopes at: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html