Because of service-oriented architecture style, instead of a monolithic application , you may have several independent applications can run on their own.Let's see how to have a Spring powered standalone application with embedded Tomcat without Spring boot.
Step 1 : Add Related Dependencies to POM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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>org.junjun.spring.util</groupId> | |
<artifactId>embedded-tomcat-with-spring</artifactId> | |
<version>1.0.0</version> | |
<properties> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |
<spring.version>4.3.7.RELEASE</spring.version> | |
<tomcat.version>8.5.2</tomcat.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-webmvc</artifactId> | |
<version>${spring.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat.embed</groupId> | |
<artifactId>tomcat-embed-core</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat.embed</groupId> | |
<artifactId>tomcat-embed-jasper</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat.embed</groupId> | |
<artifactId>tomcat-embed-jasper</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat</groupId> | |
<artifactId>tomcat-jasper</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat</groupId> | |
<artifactId>tomcat-jasper-el</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat</groupId> | |
<artifactId>tomcat-jsp-api</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>jstl</artifactId> | |
<version>1.2</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.tomcat.embed</groupId> | |
<artifactId>tomcat-embed-logging-log4j</artifactId> | |
<version>${tomcat.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>log4j</groupId> | |
<artifactId>log4j</artifactId> | |
<version>1.2.17</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.3</version> | |
<configuration> | |
<source>1.8</source> | |
<target>1.8</target> | |
</configuration> | |
</plugin> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-jar-plugin</artifactId> | |
<configuration> | |
<archive> | |
<manifest> | |
<addClasspath>true</addClasspath> | |
<classpathPrefix>lib/</classpathPrefix> | |
<mainClass>org.junjun.util.spring.AppLauncher</mainClass> | |
</manifest> | |
<manifestEntries> | |
<Class-Path>conf/</Class-Path> | |
</manifestEntries> | |
</archive> | |
<includes> | |
<include>**/*.class</include> | |
<include>*.properties.not.configurable</include> | |
</includes> | |
</configuration> | |
</plugin> | |
<plugin> | |
<artifactId>maven-assembly-plugin</artifactId> | |
<executions> | |
<execution> | |
<id>build-distribution</id> | |
<phase>verify</phase> | |
<goals> | |
<goal>attached</goal> | |
</goals> | |
</execution> | |
</executions> | |
<configuration> | |
<descriptors> | |
<descriptor>src/assembly/dist-build.xml</descriptor> | |
</descriptors> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
Step 2 : Define A Class Which Would Create , Start and Stop Tomcat Server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.server; | |
import java.util.Date; | |
import javax.annotation.PostConstruct; | |
import javax.annotation.PreDestroy; | |
import org.apache.catalina.LifecycleException; | |
import org.apache.catalina.core.StandardContext; | |
import org.apache.catalina.startup.Tomcat; | |
import org.apache.log4j.Logger; | |
import org.junjun.util.spring.AppLauncher; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.stereotype.Component; | |
@Component | |
public class EmbeddedTomcat { | |
private static final Logger log = org.apache.log4j.Logger.getLogger(EmbeddedTomcat.class); | |
@Value("${tomcat.web.content.folder.path:src/main/webapp/}") | |
private String webContentFolder; | |
@Value("${tomcat.web.base.folder.path:target/}") | |
private String webBaseFolder; | |
@Value("${tomcat.port:7070}") | |
private String port; | |
private Tomcat tomcat = new Tomcat(); | |
@PostConstruct | |
public void start() throws Exception { | |
System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true"); | |
tomcat.setPort(Integer.valueOf(port)); | |
tomcat.setBaseDir(webBaseFolder); | |
StandardContext ctx = (StandardContext) tomcat.addWebapp("", webContentFolder); | |
ctx.setParentClassLoader(AppLauncher.class.getClassLoader()); | |
tomcat.start(); | |
log.info("Tomcat Server Started at " + new Date()); | |
tomcat.getServer().await(); | |
} | |
@PreDestroy | |
public void stop() throws LifecycleException { | |
tomcat.stop(); | |
} | |
} |
Step 3 : Define Class Which Would Launch The Application and Initialize The Embedded Tomcat Server.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring; | |
import org.apache.log4j.Logger; | |
import org.junjun.util.spring.server.ServerConfig; | |
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
public class AppLauncher { | |
private static final Logger log = Logger.getLogger(AppLauncher.class); | |
public static void main(String[] ars) { | |
AnnotationConfigApplicationContext ctx = null; | |
try { | |
ctx = new AnnotationConfigApplicationContext(); | |
ctx.register(ServerConfig.class); | |
ctx.refresh(); | |
ctx.start(); | |
} catch (Exception e) { | |
log.error(e.getMessage(), e); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.server; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.PropertySource; | |
@Configuration | |
@ComponentScan(basePackages = { "org.junjun.util.spring.server"}) | |
@PropertySource("classpath:server.properties") | |
public class ServerConfig { | |
} |
Step 4 : Define Web Application Initializer And Enable Spring MVC Configuration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.server; | |
import javax.servlet.ServletContext; | |
import javax.servlet.ServletException; | |
import javax.servlet.ServletRegistration; | |
import org.junjun.util.spring.config.AppConfig; | |
import org.junjun.util.spring.config.WebConfig; | |
import org.springframework.web.WebApplicationInitializer; | |
import org.springframework.web.context.ContextLoaderListener; | |
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; | |
import org.springframework.web.servlet.DispatcherServlet; | |
public class WebInit implements WebApplicationInitializer { | |
@Override | |
public void onStartup(ServletContext container) throws ServletException { | |
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); | |
rootContext.register(AppConfig.class); | |
ContextLoaderListener contextLoaderListener = new ContextLoaderListener(rootContext); | |
container.addListener(contextLoaderListener); | |
AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext(); | |
servletContext.register(WebConfig.class); | |
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", | |
new DispatcherServlet(servletContext)); | |
dispatcher.setLoadOnStartup(1); | |
dispatcher.addMapping("/"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.config; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
@Configuration | |
@ComponentScan(basePackages = { "org.junjun.util.spring.service"}) | |
public class AppConfig { | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.config; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.web.servlet.ViewResolver; | |
import org.springframework.web.servlet.config.annotation.EnableWebMvc; | |
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; | |
import org.springframework.web.servlet.view.InternalResourceViewResolver; | |
import org.springframework.web.servlet.view.JstlView; | |
@Configuration | |
@ComponentScan(basePackages = { "org.junjun.util.spring.controller" }) | |
@EnableWebMvc | |
public class WebConfig extends WebMvcConfigurerAdapter { | |
@Bean | |
public ViewResolver internalResourceViewResolver() { | |
InternalResourceViewResolver bean = new InternalResourceViewResolver(); | |
bean.setViewClass(JstlView.class); | |
bean.setPrefix("/WEB-INF/view/"); | |
bean.setSuffix(".jsp"); | |
return bean; | |
} | |
} |
Step 5 : Define Controller and Service Layer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.controller; | |
import org.junjun.util.spring.service.EchoService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.ui.Model; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.context.request.WebRequest; | |
@Controller | |
public class WelcomeController { | |
@Autowired | |
private EchoService echoService; | |
@RequestMapping(value = "/echo") | |
public String test(WebRequest request, Model model) { | |
model.addAttribute("message", echoService.execute("ECHO")); | |
return "welcome"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.service; | |
public interface EchoService { | |
String execute(String message); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.spring.service; | |
import org.springframework.stereotype.Component; | |
@Component | |
public class EchoServiceImpl implements EchoService { | |
@Override | |
public String execute(String message) { | |
return message + " Powered By Embeded Tomcat !"; | |
} | |
} |
Step 6: Define Web Page
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="div-msg" width="100%" | |
style="font-family: Verdana, Geneva, sans-serif; font-size: 30px; text-align: center; padding-top: 100px;"> | |
${message}</div> |
Step 7 : Run Class ApplicationLauncher and Check Web Page at http://localhost:6060/echo
Step 8 : Or "java -jar embedded-tomcat-with-spring-1.0.0.jar" from embedded-tomcat-with-spring-1.0.0.tar.gz by "mvn clean install"
You may refer to source code here :
https://github.com/junjun-dachi/spring-util/tree/master/embedded-tomcat-with-spring
JOB DONE
great
ReplyDeleteHii,
ReplyDeleteI am trying to develop a standalone rest api with embedded tomcat in the same manner you are doing, only difference is that I have a restcontroller with no jsp to render the output. I want to invoke a api on controller and it should return the output as a json or a string. How to bypass the model and view here.
Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
ReplyDeleteSalesforce Training in Chennai | Certification | Online Course | Salesforce Training in Bangalore | Certification | Online Course | Salesforce Training in Hyderabad | Certification | Online Course | Salesforce Training in Pune | Certification | Online Course | Salesforce Certification Online Training Courses
I appreciate that you produced this wonderful article to help us get more knowledge about this topic.
ReplyDeleteI know, it is not an easy task to write such a big article in one day, I've tried that and I've failed. But, here you are, trying the big task and finishing it off and getting good comments and ratings. That is one hell of a job done!
angular js training in chennai
angular js training in omr
full stack training in chennai
full stack training in omr
php training in chennai
php training in omr
photoshop training in chennai
photoshop training in omr
Thanks for any other wonderful post. Where else may just anyone get that type of info in such a perfect means of writing? I’ve a presentation next week, and I am on the look for such information.
ReplyDeletesap training in chennai
sap training in velachery
azure training in chennai
azure training in velachery
cyber security course in chennai
cyber security course in velachery
ethical hacking course in chennai
ethical hacking course in velachery
Hi. Here you are pretending the 'EmbededServer' as a Spring component (therefore as a part of application context). Is it possible to run the embedded tomcat server separately from Spring application context but still use the Spring DispatcherServlet?
ReplyDelete