Can we bundle multiple spring-boot application as a war and deploy - spring

We have multiple boot component as well as different schema for each component. We have a business requirement where we need to deliver everything as a war and has to be deployed as a single application on different machine.
I am trying to go with plugin architecture, so that one(new) aggregator microservice will be prepared where we can add every boot component as a plugin and then use them as a bundle(war) deployable.
By enabling a component with maven plugin we have created two jar one executable jar and another original jar. But how do i add them in to the new aggregator component as a plugin and access the rest layer from each component(plugin).
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4.RELEASE</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
Do i need any change in approach/ how do i add a spring-boot jar as a plugin to another project? Any references or sample structure/code would be helpful & thanks in advance.

Related

Unable to use class from Custom Spring boot library

Goal
I want to use a private repository as a library in other spring boot projects by hosting it as a GitHub package.
Library project
https://github.com/sagarnayak/privatecentralrepo
Client Project
https://github.com/sagarnayak/repoclientproject
Steps To Reproduce
the library project has a library001 module. this is what I want to use as a library for other projects.
In the library module pom file, I have added the repackage execution goal.
......
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
......
I want to use the module as a library and host it as a private GitHub package.
When I do the mvnw deploy in the library001 module this should create an exec jar and push to GitHub to use this library in other projects.
Github has this exec jar.
To use the jar in the client project I have added this as a dependency in the client project.
<dependency>
<groupId>com.sagar</groupId>
<artifactId>libraray001</artifactId>
<version>0.0.3-SNAPSHOT</version>
<classifier>exec</classifier>
</dependency>
This gets the project into the external libraries part of the client project. and this has the class that I want to use in the library (TestModel001).
But when I try to import this into any classes that I want to use it can not resolve the import.
How do I use the library project in this project?
I solved the issue with this -
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
The issue was with the pom file.
I was using the configurations for an older version.
The client project as visible at sagarnayak/repoclientproject is not configured to consume the artifacts from the private Maven repository hosted on GitHub as described in the Working with the Apache Maven registry.
Specifically, following settings are missing:
<repositories> configuration in pom.xml
<servers> configuration in local settings.xml
Add following elements to the pom.xml:
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/sagarnayak/</url>
</repository>
</repositories>
Add following elements to the settings.xml
<servers>
<server>
<id>github</id>
<username>sagarnayak</username>
<password>YOUR_PERSONAL_ACCESS_TOKEN_HERE</password>
</server>
</servers>
Note: Keep settings.xml local to your machine - don't leak that Personal Access Token!
You are packaging the library via spring-boot-maven-plugin
It produces a JAR that has a self-running spring boot structure, and so you are unable to import it as a library correctly.
Try to remove spring-boot-maven-plugin from your libraray001 pom.xml, rebuild, republish and try to consume that artifact in your client project again, refreshing the dependencies and preferably bumping up the library version, to exclude caching possibility during the test.

How should I run front end integration tests in spring boot?

I have a simple spring boot project that has a maven structure like this:
project
- backend (spring boot)
- frontend (angular)
I got the project configured so *IT.java classes run during integration test phase of maven and they are successfully testing the Spring Boot REST API with an H2 database.
I'm trying to configure the project so my cucumber tests that interact with the browser will run during the integration test phase of the project. The cucumber tests start up ok but fail for the simple reason the angular files don't get served by the spring boot application when it starts.
In backend/src/main/resources/static I have a simple index.html file. When the cucumber tests run they open a browser an I see the content of that file.
In the backend module (war) pom I copy the dist content from the angular build...
<build>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>some.package.Boot</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<warName>${root.context}</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<resources>
<resource>
<directory>../frontend/<appname>/dist/frontend</directory>
<!--<targetPath>src/main/resources/static</targetPath>-->
<targetPath>static</targetPath>
</resource>
</resources>
</build>
In the resultant war file the angular files are packaged up into WEB-INF/classes/static/.
You'll note from above I also tried getting the angular code copied into resources/static, but that puts the files in target/classes/src/main/resources/static, so that isn't the right approach!
Yet the cucumber tests still only see the content of the index.html file from src/main/resources/static when they run.
Potentially we could move the angular app into the same src tree as the java/webapp code, but that's not an option.
How can I persuade Spring Boot to use the war in target rather what it appears to be doing and service content from source?
Versions:
Java 11
Maven war plugin 3.2.2
Springboot version defined in parent pom as 2.1.3.RELEASE
spring-boot-starter-web
spring-boot-starter-data-rest
spring-boot-starter-data-jpa
spring-boot-starter-data-jdbc
spring-boot-starter-tomcat (not sure I need this one)

Different packaging with Spring Maven Plugin: Spring + Spark application

I have a project which consists of three parts:
Spring Boot application
Spark Application
"Library" used by both of the above (having this library as separate JAR or similar causes quiet a bit of overhead and slowed down the development)
So what I want is a JAR that can be used to run the Spring Boot app (java -jar myapp.jar) as well as the Spark app (java -cp myapp.jar path.to.main.class).
It is also OK to have two JARs - but both would need to be fat JARs (meaning: include dependencies).
What I tried in the pom.xml is this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
This creates (as expected) a fat JAR that can be used to run the Spring Boot app. But it cannot be used for the Spark app (as the classes and dependencies are somehow repackaged as I understand).
My second try was this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
This creates the fat JAR as well plus another JAR just holding the classes that are implemented in my project - but without the dependencies. Therefore the Spark job does not start (as expected).
Any idea how to solve this situation?
Thanks!
I used the same technology stack for an application (Spring- for the web part and Apache Spark for the big data processing). I don't see the case where someone wants to build a fat jar for both the side, Spring + Spark (except the case where inside spark jobs you would use something from Spring). So, the approach that we use is to have to separate Maven module one for the Spring web part and one for the Apache Spark. For the Spring Boot we did not use the spring-boot-maven-plugin, but instead we used the following maven plugins, something like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<mainClass>com.Application</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<excludeArtifactIds>integration</excludeArtifactIds>
<outputDirectory>${project.build.directory}/lib/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Like this we have a better controller use all the dependencies (e.g: put then in a lib folder and include them in MANIFEST)
For the Spark application you have two option:
run with spark-submit (personally i don't prefer it)
use SparkLauncher class from spark_launcher*.jar dependency (calling from web a Spark Job).
Building a fat jar for Spark application with only dependencies used in Spark code is desirable, cause you load only what you truly need. We can use maven-shade-plugin for this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
// put here what you need to include
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
Using maven shade plugin is not encouraged, unless and until there is no other option apart from using the maven shade plugin. Below is the informative link for not to use the shade plugin.
Downsides of using Shade plugin relocation feature
From my perspective for running spark application, spring boot maven plugin is the best option for managing everything, including library dependencies. Even if your application is used as a scheduled job, in which you need to use spark-submit/spark launcher for launching the application.
In other case where your java app using spark and spring both but have controller/api to use the application in that case also spring boot maven plugin is the best one.
There are only 2 types of Challanges when we use spark-submit/spark launcher to launch the application which is created using spring boot maven plugin.
1. Main Class
When we package fat jar/uber jar using spring boot maven plugin, it is packging the class files and java libraries in spring way and not the way sprak is expecting it.Inside the uber jar generated by the spring boot maven plugin, we have boot-inf,meta-inf and org folder.So when we give mainclass in spark submit or spark launcher as a parameter,It will not able to find that class as it will not be able to locate package/path specified in parameter, due to change of structure in jar file.Even after you specify the correct location which is starting with BOOT-INF for main class, it will not work because the way spring launches the application is using differrent main class.
Below is the link which shows main class that should be used for launching the fat jar generated by spring boot maven plugin.
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#appendix.executable-jar.launching
On high level if I inform ,File named as MANIFEST.MF inside the uber jar contains below entries.Where Main-Class is the actual main class which is used for initialization of spring related stuff, after which customized main class should get started which is Start-Class entry.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication
So as a conclusion specifiying main class as "org.springframework.boot.loader.JarLauncher" in spark-submit or spark-launcher will resolve our issue for this problem.This will only work if you are using sparing boot maven plugin for packagin the jar.
External common libraries used in pom.xml+spark installation.
Another issue which might occure while using spark-submit or launcher application while launching uber jar, packaged using the spring boot maven plugin is jar conflicts.So the problem will be when we package jar using spring boot maven plugin, it is coping depedencies inside BOOT-INF/lib folder, let's say if you are using below depedency in pom.xml.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
Now let's say this depedency already exist with differrent version in spark installation, in that case it will give conflict in classes.As it will be an issue of class loader ,its better not to use those which might create conflict due to which application might fail.I have faced this kind of issues related to logger classes or json libraries, as there are multiple json/logger library options are available.As a resolution you can excluded those classes or libraries or you can replace that library with alternative one.

Deploy Java EE Wildfly REST Application to Openshift

I am new to Openshift and having trouble with deploying my Java EE project to it. I have made REST API for a simple webstore. Locally it works fine on Wildfly 9.0.2 I want to deploy it on openshift. I 've made new wildfly9 + mysql5.5 application using eclipse openshit jboss plugin and added a profile to root pom.xml:
<profiles>
<profile>
<id>openshift</id>
<build>
<finalName>webstore</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<outputDirectory>deployments</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
My root project consist of several maven modules including store-ear (EAR), store-jpa (JAR), store-rest (WAR), store-web (WAR), store-services (EJB), store-rest-interfaces (JAR),store-service-interfaces (JAR).
I have changed datasourse in JPA configuration (persistence.xml) to use MysqlDB on Openshift.
After pushing back to openshift the build is succesfull, but when it gets deployed it is missing some dependancies (ClassNotFoundException), and fails to deploy main war file.
You use a maven-war plugin in your openshift maven profile.
But you say that your project is packaged as en ear. So you should probably deploy this ear which contains all your project modules (wars, ejbs, libs...) instead of a specific war of your project.
To achieve this, you have to use a maven-ear plugin instead of the maven-war one in your openshift profile which would look like this:
<profile>
<id>openshift</id>
<build>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10</version>
<configuration>
<outputDirectory>deployments</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>

Make jar library from web project (netbeans, maven, web)

I'm using Netbeans 8 in my maven web application.
I need to export a jar library from my web application with only my own custom classes (not dependencies etc).
How can I achieve that in a neat way. The IDE only generates a .war, I need that custom .jar also to be used elsewhere.
thx.
Well, I found a solution and worked:
Adding this in pom.xml inside /project/build/plugins
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
<classesClassifier>classes</classesClassifier>
</configuration>
</plugin>

Resources