We build proof-of-concept JAR and WAR Spring Boot application and show how to run it on shared cPanel server using any of our Java hosting packages.
We use JDK 8 and Maven 3.2 that are available with any Java hosting package. No IDE will be used but commands typed directly in shell for this simple task.
Check that Java and Maven are ready:
java -version
mvn -v
The below POM allows for generating JAR and WAR with only 1 change: the packaging
attribute. First we POM will generate JAR. Later we will update it so that it generates a WAR i.e. add <packaging>war</packaging>
. For testing WAR we will use a standalone Tomcat that runs beside.
cat > pom.xml<<EOF
<?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>
<groupId>com.example</groupId>
<artifactId>SpringBootTester</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<dependencies>
<!-- Add Tomcat and Spring MVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Skip the following dependency if you are not going to use the application with external Tomcat. Embedded Tomcat does not need it. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- We defintely need below for Maven to process Spring Boot apps. -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EOF
Embedded servlet container dependency is marked as ‘provided’. Generated WAR will contain dependencies marked this way in lib-provided
directory. In effect you will also be able to run the application using java -jar
that we will test below.
Now the Java code. @RestController
will allow us to skip creation of view file (template) needed for regular @Controller
. @RequestMapping("/")
maps application’s root URL (not domain URL) to the hello
function. If the application will be deployed as ROOT.war then application’s root URL will equal domain’s root URL.
mkdir -p src/main/java
cat > src/main/java/Example.java<<EOF
package com.example;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
@RestController
@SpringBootApplication
public class Example extends SpringBootServletInitializer {
@RequestMapping("/")
String hello() {
return "Hello World from JAR or WAR!";
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Example.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}
EOF
Testing embedded Tomcat via ‘spring-boot:run’
mvn spring-boot:run
Ctrl+C will shutdown the embedded server. On another terminal reach the URL:
curl http://springboot.budgetjava.com:8080/
Hello World from JAR or WAR!
Testing JAR at custom port
mvn package
java $JAVA_OPTS -Dserver.port=11188 -jar target/SpringBootTester-0.1.jar
curl http://springboot.budgetjava.com:11188/
Hello World from JAR or WAR!
Ctrl+C will shutdown the process if it runs in foreground. Of course you can leave it running in background and logging to a file by appending &>log &
at the end of the java -jar ...
command.
Testing WAR in external Tomcat listening on default HTTP port
We need to modify packaging line first.
sed -i -re 's/(<packaging>)jar(<\/packaging>)/\1war\2/' pom.xml
mvn clean package
cp target/SpringBootTester-0.1.war $CATALINA_HOME/webapps
Wait until it deploys by tracing log with tail -f $CATALINA_HOME/logs/catalina.out
. On another terminal check:
curl http://springboot.budgetjava.com/SpringBootTester-0.1/
Hello World from JAR or WAR!
You might also have copied it to $CATALINA_HOME/webapps/ROOT.war
to have it served at domain’s root URL. See how main class changes in MANIFEST.MF
depending on what you set in pom.xml
:
unzip -c target/SpringBootTester-0.1.war META-INF/MANIFEST.MF | grep Class
Start-Class: com.example.Example
Main-Class: org.springframework.boot.loader.WarLauncher
unzip -c target/SpringBootTester-0.1.jar META-INF/MANIFEST.MF | grep Class
Start-Class: com.example.Example
Main-Class: org.springframework.boot.loader.JarLauncher
There are many alternative ways of presetting server.port for example in src/main/resources/application.properties
:
server.port=8888
or in src/main/resources/application.yml
server:
port: 8888
Here are the SpringBootTester-0.1.jar and SpringBootTester-0.1.war for your reference.
For SpringBoot 2.0 SpringBootServletInitializer
is in the org.springframework.boot.web.servlet.support
package so the complete example could look like this:
<?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 https://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.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</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>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
src/main/java/DemoApplication.java:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, (String[])args);
}
}
src/main/java/controller/HelloController.java:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping(value={"/say"})
public String sayHello() {
return "{ \"name\":\"John Doe\"}";
}
}
Build WAR as usual with mvn clean package
and finally deploy to Tomcat’s webapps and check with curl http://domain.com/demo/say
.
Get testing demo WAR demo-2.2.2-SNAPSHOT.war) and use it with Tomcat 9.x.
For SpringBoot 3.0 (get testing demo WAR demo-3.0.4-SNAPSHOT.war) please use Java 17+ and Tomcat 10.x. You may also need to comment out default servlets (default
and jsp
) and their mappings in Tomcat’s conf/web.xml
to avoid Spring security method cannot decide pattern is mvc or not
Spring Boot application exception.
For SpringBoot 3.3.1 here is the demo-3.3.1-SNAPSHOT.war and here is the source code demo-3.3.1-SNAPSHOT.src.zip.