Every developer dreams of working with modern technologies and staying up-to-date. In fact, it's nearly impossible to build a strong hiring strategy around outdated, obsolete, and often ineffective and even stillborn technologies.
However, life is complex, and not everything always depends on our desires.
You might be offered a promotion and transferred to a project where the technologies haven't changed or been updated in years. Or, you could land a job at your dream company, where the current technology stack doesn't particularly interest you at the moment. Perhaps you've just graduated from university and are eager to gain your first work experience, or maybe you've been laid off from your previous job and need to find something quickly to avoid financial hardship.
There's also another scenario: during the interview, you're told that you’ll start working with the current stack but will have plenty of opportunities to make changes in the future—maybe, possibly, but...
But let's be honest, this is all just philosophy. I agree, and I propose we analyze some potential case that you might encounter on your challenging career path.
For all fans of the JVM stack, especially those who love the Spring Framework, this is for you, please, read on.
BTW, why would you even need to deploy a Spring Boot application on an application server when it can run independently? After all, that’s one of Spring Boot's standout features.
And so, there may be several reasons for this:
Java 8 was released on 18th March 2014 and brought milestone features that we use to this day.
I don't need to go far for examples, here are just some of them:
Lambda Expressions
Stream API
Optional Class
The java.time Package (Date and Time API)
etc etc
Since then, three LTS versions have been released to this day(19/08/2024):
According to a study conducted by New Relic, Java 8 is still used in 28.8% of current projects, which, as you’ll agree, is not insignificant. While its share is gradually declining year by year, it's certainly too early to dismiss this technology entirely.
According to the Project Eclipse website dedicated to Eclipse GlassFish:
Eclipse GlassFish® is a complete application server that implements the Jakarta EE specification. GlassFish includes implementations of all required and optional Jakarta EE APIs, and passes all Jakarta EE TCKs. GlassFish also includes a complete administration console, clustering support, and other developer and production focused tools and features.
Unfortunately, it’s not possible to download from this website version younger than 5.1.0, but since we decided to use the version below the fifth, we will have to go to the Oracle website, where you can find several earlier versions of this product in the Downloads section. But be careful with the license and don’t use anything from this folder outside of your sandbox.
Simply place the distribution file somewhere on your machine, navigate to the bin
folder, and run the following command:
./asadmin start-domain --verbose
Wait for a while, and try to open http://localhost:4848/, the Admin Console should be available by default and shouldn’t ask for any kind of credentials. On the left panel, you will find the Applications tab, if you click on it, you will have access to a menu with which you can deploy, undeploy, enable, and disable applications.
That's all you need to know about GlassFish at the moment to try to deploy your application there.
It's probably quite difficult to find a person in the world of web development who hasn't heard of this popular framework at least once.
Spring Boot 2 was released in 2021 and requires Java 8 as a minimum version unlike version 3 which requires Java 17 as a minimum version.
To be able to use the latest features, security patches, and some optimizations we have to find the latest version which supports Java 8.
And here it is, 2.7.18, according to their blog, 2.7.18 became the latest version of support Spring Boot 2.x and accordingly Java 8 and Java 11:
After 5.5 years and 121 releases, 2.7.18 marks the end of open source support for Spring Boot 2.x. Please upgrade to Spring Boot 3 as soon as possible. If you are not yet ready to upgrade, commercial support for Spring Boot 2.7.x is available.
Spring Boot Community provides recommendations on how to run Spring Boot Application in EE environment + Official Documentation
The minimum and sufficient pom.xml for building and running the application will look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<groupId>io.github.isharipov</groupId>
<artifactId>sb2-to-gf4</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here you need to pay attention to two things:
I’m packaging the application as a war file to make it clear to the application server that I am deploying a web application
<packaging>war</packaging>
I’m excluding embedded Tomcat adding spring-boot-starter-tomcat dependency excluding two internal dependencies and adding the provided scope
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
This approach allows you to include Tomcat and make it available only for the Spring Boot runtime, enabling you to run the application independently from the application server. This separation is important. Spring places this dependency into a separate folder called lib-provided within the resulting artifact. You now have at least three options for running the resulting artifact:
domain-dir/autodeploy
asadmin
API - deploy commandjava -jar
: spring-boot-maven-plugin creates two artifacts - war
and war.original
. The simple war
includes lib-provided
, original
one doesn’t.Excluding the following dependencies allows us to reduce the resulting artifact size:
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
To run a Spring Boot application on an application server, you'll need to make two modifications to the main application class.
Typically, to set up a simple web application, you would create a public class with a main
method, and annotate it with @SpringBootApplication annotation.
@SpringBootApplication
public class Application {
private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
So, as I mentioned above, two amendments:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
LOGGER.debug("From main");
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
LOGGER.debug("From configure");
return application.sources(Application.class);
}
}
And last but not least, you need to add Deployment Descriptor
So, under the main → src → webapp → WEB-INF folder you need to put the following file - glassfish-web.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<class-loader delegate="false"/>
<session-config>
<session-manager/>
</session-config>
<jsp-config/>
</glassfish-web-app>
Read more about Deployment Descriptor
Read more about Class Loader Delegation