Why isn't this jar packaging valid for Spring Boot? - spring

I am trying to understand the packaging of Spring Boot into "fat" jars. From what I know "fat" jars have their own special classes that load up the main class when the jar is running and also sets the classpath accordingly.
What I cannot understand is why when I use Eclipse to extract all my dependencies into a folder structure in the jar, the jar no longer runs as a correct Spring Boot application.
To repeat what I have done here just take a simple Spring Boot app and from Eclipse select the following-:
Export --> Runnable Jar --> Select Main Class --> Extract required libraries into jar.
Just run the jar from the command line as you would any jar. Spring Boot initially starts up but fails with the following message-:
2017-05-02 22:06:40.484 WARN 3468 --- [ main]
ationConfigEmbeddedWebA pplicationContext : Exception encountered
during context initialization - cancel ling refresh attempt:
org.springframework.beans.factory.BeanDefinitionStoreExcep tion:
Failed to process import candidates for configuration class
[com.main.Test Main]; nested exception is
java.lang.IllegalArgumentException: No auto configuration classes
found in META-INF/spring.factories. If you are using a custom packa
ging, make sure that file is correct.
Can I somehow edit the spring.factories file to include my classses ?
I just trying to understand how Spring actually packages the files through its Maven plugin.

I think that because it's a Spring Boot application, you need to use their plugin for building. It is because, spring Boot has its own jar loading mechanism for that (the BOOT-INF introduction in Spring Boot 1.4).
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
From documentation:
The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application “in-place”.
Link to documetantion (Appendix E)
Something about spring.factories and locating auto-configuration candidates - Auto-configuration

Related

Difference between Spring boot 2.5.0 generated *jar and *-plain.jar?

I upgraded my spring boot app to 2.5.0, then is app.jar and app-plain.jar is created by gradle.
I would like to the difference between these jars.
thanks
app.jar is the archive produced by the bootJar task. This is a Spring Boot fat jar that contains all of the module's dependencies as well as its classes and resources. It can be run using java -jar.
app-plain.jar is the archive produced by the jar task. This is a plain or standard jar file that contains only the module's classes and resources.
You can learn a bit more about this in the documentation for Spring Boot's Gradle plugin.

my application.properties from dependency is not available in spring boot application

I have spring boot application.
In this spring boot (fat-jar) application I have classpath:config/application.properties and classpath:application-env.properties.
I am starting this application using command:
java -Dspring.profiles.active=env -jar application.jar --some-parameter=some-value
Question: Why application.properties file is not available during initialization this application from classes (beans) localized in my dependency?
This file (application.properties) is localized in classpath:application.properties of my dependency.
I am expecting some properties with some specific prefix - using annotation:
#ConfigurationProperties(prefix = "someprefix")
and again the same in other words:
Application A have classpath:config/application.properties
+ Application A have/is using dependency to some artifact D
dependency (jar) D.jar have classpath:application.properties
this application.properies is not available during initialization of bean B with annotatin #ConfigurationProperties(prefix = "someprefix")
according to 24.3 Application property files "The classpath root" should be fine - but it is not.
This is fat-jar application - in one big jar we have everything - including folder 'lib' with all dependencies.
OK, :(
solution of my issue was trivial. My application was loading different classpath:/application.properites than I thought.
I had another dependency jar introduced to my project not-directly (it was dependency for my dependency) which contains different classpath:/application.properites.
In other words everything works fine but only one 'classpath:/application.properties' is loaded even you have two in two different dependencies.
I used /actuator/env to find out which classpath:/application.dependency was loaded.

Use of spring-boot-maven-plugin

While creating a spring boot project I define property in pom.xml as <packaging>war</packaging> with which I can create a war and thereafter deploy the war into server maybe tomcat or WAS.
But I came across a plugin named spring-boot-maven-plugin whose documentation states that it's use is to package executable jar or war archives and run an application in-place.
My query is why do we need this at all ?
If my packaging can tell me what to create and then can deploy it to run, what is the used of this plugin.
I am trying to understand a new project so wanted to be sure that every line makes sense
The maven plugin will create an "executable" archive. In the case of the war packaging, you would be able to execute your app with java -jar my-app.war. If you intend to deploy your Spring Boot application in an existing Servlet container, then this plugin is, indeed, not necessary.
The maven plugin does more things like running your app from the shell or creating build information.
Check the documentation
The Spring Boot Maven Plugin provides Spring Boot support in Apache Maven, letting you package executable jar or war archives and run an application “in-place”.
Refer this - https://www.javaguides.net/2019/02/use-of-spring-boot-maven-plugin-with.html

Spring WebApplicationInitializer (ServletContainerInitializer, #HandlesTypes) with Embedded Tomcat

I fail to understand why in the following minimal project my implementation of Spring's WebApplicationInitializer interface is found when running tests within Eclipse and IntelliJ, but not when using Maven (mvn clean test).
With Eclipse and IntellIJ I see INFO: Spring WebApplicationInitializers detected on classpath: [com.example.pack.DummyInitializer#26d678a4]
With mvn clean test I see INFO: No Spring WebApplicationInitializer types detected on classpath.
In the test I start an Embedded Tomcat:
String pathToWebXML = new File("src/main/webapp/").getAbsolutePath();
tomcat = new Tomcat();
tomcat.setBaseDir("embedded_tomcat");
tomcat.setPort(0);
tomcat.addWebapp("", pathToWebXML);
tomcat.start();
The web.xml references a ServletContextListener implementation which creates a new (and empty) AnnotationConfigWebApplicationContext.
I uploaded the example project to GitHub: https://github.com/C-Otto/webapplicationinitializer
As indicated in the comments, the classpath used by Maven Surefire (and Maven Failsafe) in the default setting is not scanned by Tomcat. Most classes are referenced using a MANIFEST.MF file inside a JAR file.
One option is to disable the useSystemClassLoader setting of the Maven plugins. However, this changes the details of the classloader, which may cause other problems.
As another option one could disable useManifestOnlyJar, which may cause problems on Windows machine.
In our project we decided to remove the initializer classes, and instead register whatever they were supposed to do manually. In a concrete example, as our implementation of AbstractSecurityWebApplicationInitializer was not found, we now register the security filter manually inside the contextInitialized method:
String filterName = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
servletContext.addFilter(filterName, new DelegatingFilterProxy(filterName)).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
You can tell Tomcat to include the jars that are referenced via the manifest file in the jar created by surefire. This can be done in context.xml setting the Jar Scanner attribute scanManifest to true. This is the default in newer versions of Tomcat as stated here: https://bz.apache.org/bugzilla/show_bug.cgi?id=59961.

spring boot System.getProperty("java.class.path") doesn't include lib/ jars

I've got a spring boot app and I'm building a myApp.jar using the spring-boot antlib. When I jar -tf myApp.jar I see that I have a jar called lib/foo.jar. Yet when I print out System.getProperty("java.class.path") I don't see that jar file on the classpath. I also get a ClassNotFound exception from URLClassLoader when the code attempts to use this class for the first time. I'm using the JarLauncher since that's what the antlib defaults to.
Any ideas why this jar file would not be on the classpath?
You won't see a bundled JAR in System.getProperty('java.class.path'). The class path specifies where the JVM will look in the filesystem for classes you attempt to load.
Spring Boot uses fat JARs, which are loaded in a completely different way. Refer to the Spring Boot documentation.

Resources