Deploying SpringBoot (rest services) war via IntelliJ on Tomcat gives 404's - maven

Starting a small SpringBoot application by running the application (directly), the REST service localhost:8080/xyz/a gives a correct JSON result.
Via IntelliJ I configured a Tomcat server. I added this WAR with a context root of '/contextroot'. So I expected the URL REST to be localhost:8080/contextroot/xyz/a. This keeps on getting 404 errors.
Can you help me getting the right configuration or URL?
Is there a way to see which URL's are mapped from the controller to the URL's? Or: how can I solve these mapping issues more easily (from Tomcat)?
In the Maven Pom.xml I have:
<groupId>nl.xyz</groupId>
<artifactId>contextroot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>contextroot</name>
<packaging>war</packaging>
The within is also contextroot.

#Jonhib - thank you for helping.
The problem was the way I deployed a SpringBoot (jar) application as a WAR.
Take these 3 steps to change a SpringBoot standard application into a deployable (old fashioned) WAR. This is needed because I deploy it together with a Angular4 application.
Step 1 - Change the standard SpringBoot application:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application .class);
}
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
Change the target of the building process from 'jar' into a 'war'.
<packaging>war</packaging>
Add a new dependency into the pom.xml maven file:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
...
</dependencies>

Related

ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean

I have written a spring batch application using Spring boot. When I am trying to run that application using command line and classpath on my local system it is running fine. However, when I tried to run it on linux server it is giving me following exception
Unable to start web server; nested exception is
org.springframework.context.ApplicationContextException:
Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
Below is the way I am running it:
java -cp jarFileName.jar; lib\* -Dlogging.level.org.springframework=DEBUG -Dspring.profiles.active=dev -Dspring.batch.job.names=abcBatchJob com.aa.bb.StartSpringBatch > somelogs.log
Case 1:
#SpringBootApplication annotation missing in your spring boot starter class.
Case 2:
For non-web applications, disable web application type in the properties file.
In application.properties:
spring.main.web-application-type=none
If you use application.yml then add:
spring:
main:
web-application-type: none
For web applications, extends *SpringBootServletInitializer* in the main class.
#SpringBootApplication
public class YourAppliationName extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(YourAppliationName.class, args);
}
}
Case 3:
If you use spring-boot-starter-webflux then also add spring-boot-starter-web as dependency.
Probably you missing #SpringBootApplication in your spring boot starter class.
#SpringBootApplication
public class LoginSecurityAppApplication {
public static void main(String[] args) {
SpringApplication.run(LoginSecurityAppApplication.class, args);
}
}
The solution is:
I explicitly set the below property to none in application.yml file.
spring:
main:
web-application-type: none
My solution had to do with a bad dependency. I had:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
In my pom and I had to comment out the exclusion to get it working. It must look for this tomcat package for some reason.
In my case the issue resolved on commenting the tomcat dependencies exclusion from spring-boot-starte-web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- <exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions> -->
</dependency>
You probably use this in your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
in which case you'll have to also add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
and the magic happens :)
PS: that's because Spring will use by default web-MVC instead of web-flux when both are available
Adding following bean worked for me.
#Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
I was running non web spring application using SpringApplication.run(MyApplication.class, args); without #SpringBootApplication annotation.
Annotate class public static void main with, for example: #SpringBootApplication
To convert an Spring boot wen application to standalone:
Either configure application.properties:
spring.main.web-application-type=none
Or Update application context with NONE web context.
ApplicationContext ctx = new SpringApplicationBuilder(MigrationRunner.class)
.web(WebApplicationType.NONE).run(args);
Using application context, you can get your beans:
myBean bean = (MyBean) ctx.getBean("myBean", MyBean.class);
bean.call_a_method(..);
I had this problem during migration to Spring Boot. I've found a advice to remove dependencies and it helped. So, I removed dependency for jsp-api Project had. Also, servlet-api dependency has to be removed as well.
compileOnly group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.2'
As for me, I removed the provided scope in tomcat dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope> // remove this scope
</dependency>
I did right click on my project in IntelliJ IDEA then Maven -> Reload project, problem solved.
In case you're using IntelliJ and this is happening to you (like it did to my noob-self), ensure the Run setting has Spring Boot Application and NOT plain Application.
I was getting same error while using tomcat-jasper newer version
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>10.0.6</version>
</dependency>
I replaced with the stable older version it worked fine for me.
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.46</version>
</dependency>
Apart from the possible solutions in other answers, it is also possible that somehow Maven dependency corruption has occurred on your machine. I was facing the same error on trying to run my (Web) Spring boot application, and it got resolved by running the following -
mvn dependency:purge-local-repository -DreResolve=true
followed by
mvn package
I came onto this solution looking into another issue where Eclipse wouldn't let me run the main application class from the IDE, due to a different error, similar to one on this SO thread -> The type org.springframework.context.ConfigurableApplicationContext cannot be resolved. It is indirectly referenced from required .class files
Similar to the solution of making sure org.springframework.boot:spring-boot-starter-tomcat was installed, I was missing org.eclipse.jetty:jetty-server from my build.gradle
org.springframework.boot:spring-boot-starter-web needs a server be it Tomcat, Jetty or something else - it will compile but not run without one.
I wanted to run the WAR type spring boot application, and when I was trying to run the app as spring boot application I was getting above error. So declaring the web application type in application.properties has worked for me.
spring.main.web-application-type=none
Possible web application type:
NONE - the application should not run as a web application and should not start an embedded web server.
REACTIVE - the application should run as a reactive web application and should start an embedded reactive web server.
SERVLET - the application should run as a servlet-based web application and should start an embedded servlet web server.
In my case, the problem was I didn't had a Tomcat server separately installed in my eclipse. I assumed my Springboot will start the server automatically within itself.
Since my main class extends SpringBootServletInitializer and override configure method, I definitely need a Tomcat server installed in my IDE.
To install, first download Apachce Tomcat (version 9 in my case) and create server using Servers tab.
After installation, run the main class on server.
Run As -> Run on Server
I was trying to create a web application with spring boot and I got the same error.
After inspecting I found that I was missing a dependency. So, be sure to add following dependency to your pom.xml file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Missing dependency could be cause of this issue
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
I encountered this problem when attempint to run my web application as a fat jar rather than from within my IDE (IntelliJ).
This is what worked for me. Simply adding a default profile to the application.properties file.
spring.profiles.active=default
You don't have to use default if you have already set up other specific profiles (dev/test/prod). But if you haven't this is necessary to run the application as a fat jar.
Upgrading spring-boot-starter-parent in pom.xml to the latest version fixed it for me.
In my case, I was using an TOMCAT 8 and updating to TOMCAT 9 fixed it:
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-app</groupId>
<artifactId>spring-boot-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<tomcat.version>9.0.37</tomcat.version>
</properties>
Related issues:
https://github.com/spring-projects/spring-boot/issues?q=missing+ServletWebServerFactory+bean
https://github.com/spring-projects/spring-boot/issues/22013 - Spring Boot app as a module
https://github.com/spring-projects/spring-boot/issues/19141 - Application fails to load when main class extends a base class annotated with #SpringBootApplication when spring-boot-starter-web is included as a dependency
My problem was the same as that in the original question, only that I was running via Eclipse and not cmd. Tried all the solutions listed, but didn't work. The final working solution for me, however, was while running via cmd (or can be run similarly via Eclipse). Used a modified command appended with spring config from cmd:
start java -Xms512m -Xmx1024m <and the usual parameters as needed, like PrintGC etc> -Dspring.config.location=<propertiesfiles> -jar <jar>
I guess my issue was the spring configurations not being loaded correctly.
In my case, the gretty plugin (3.0.6) was still active. Gretty somehow influences the embedded tomcat dependency. Removing gretty fixed the error
Just comment the provided like below

how load external configuration class in spring boot

I have a spring boot application
The structure of my application is:
src
main
java
org
Application.java
service
--another classes are here
Application.java
package org.baharan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
Another confirguration class files sush as oracle config and security config are in another application(is named core) is added in my pom.xml
<dependency>
<groupId>org.baharan.amad</groupId>
<artifactId>core</artifactId>
<version>1.0-releases</version>
<type>war</type>
</dependency>
When i build my application, all of classes and properties files of core application are added in my target by overlay maven
When i excute Application.java,spring boot couldn't find any config class isn't in my application but they are in core(after build all of them is added in my target)
In other word how spring boot load configuration classes which dont exist in current application.
please help me.
If they're spring configs you can still use #ComponentScan to load in other bean configs e.g.
#ComponentScan("classpath*:com.myorg.conf")
and
#ComponentScan("classpath*:conf/appCtx.xml")

Spring Boot: Running as a Java application but classpath contains spring-web

I've successfully managed to create a Spring boot application that runs as a Java application as follows:
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication springApplication = new SpringApplication();
springApplication.setWebEnvironment(false);
springApplication.run(Application.class, args);
}
The problem is that my application requires the spring-web module as it is a client to a REST service.
Once I add the spring-web module I get an error:
Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
How can I get it to run as a Java application with spring-web on the classpath
I have "same setup" as you - command line spring boot app that uses RestTemplate from spring-web and everything works well. Maybe it is just that I use "full" spring web starter.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
(and just slightly different main but it shouldn't be a difference)
SpringApplication app = new SpringApplication(MyApplication.class);
app.setWebEnvironment(false);
app.run(args);

logging.config configuration for spring boot

I wanted to configure location of log4j.xml file in my spring boot application.
For that I have added logging.config property to my application.properties configuration, indicating log4j.xml file path.
But seems this property is ignored.
But it should work accorindg to spring boot docs:
logging.config= # location of config file (default classpath:logback.xml for logback)
Have I did something wrong?
Spring Boot includes some starters that can be used if you want to exclude or swap specific technical facets. It's using logback by default, if you're gonna use log4j add spring-boot-starter-log4j in your classpath. For example, with maven it would be something like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
and for log4j 1.x:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
Then add logging.config to your application.properties:
logging.config = classpath:path/to/log4j.xml
I find out that in some cases external logging config(logback.xml)is not ignored: when application is started from application folder, it works properly.
Some clarification on this point: application is run through script, which can be called from any place.
I have not yet gone deep and found out why it works in that way, but if I provide config file path as an argument during the start up, it will work. So we just add this argument to running script:
--spring.config.location=/configPath/application.properties
Probably this problem is caused by Spring loading stages.
If you have any idea what is the root cause of this problem , please share:)
According to spring boot docs :
If you are using the starter poms for assembling dependencies that means you have to exclude Logback and then include your chosen version of Log4j instead.
like this :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
I spend few days to understand whether this should even work and I have doubts regarding this. Despite it is clearly mentioned in the documentation how to use Custom Log Configuration, some treat it differently. There many issues regarding this property is not working here and there on spring github issue tracker, like this and this. And another valid point is that logging configuration must be done as earlier as possible to correctly log application initialization. Thus system property looks like most savvy option here. And you can keep it within your application code. The only requirements would be to set it before spring context initialization.
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
// to start from command line
System.setProperty("logging.config", "classpath:portal-log4j2.yaml");
SpringApplication.run(Application.class, args);
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
// to start within container
System.setProperty("logging.config", "classpath:portal-log4j2.yaml");
// this has SpringApplication::run() inside
super.onStartup(servletContext);
}
}
Because all apps in Tomcat web container is loaded within the same JVM, there is no sense to deal with custom logging.config but use single config for the whole container with default file name.

Spring Boot + Jetty & hot deployment

I've read the Hot swapping in Spring Boot but didn't find something that will help my case.
I have a spring-boot app on embedded jetty servers using thymeleaf. My app will serve html,css,js(AngularJS) and REST services.
Folder structure is like this:
/java
----
/resources
/static
/js
/css
/templates (html)
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
But css/html/js is not hot deployed when I change them. I have to restart server every time.
+bonus = when page loads it locks resources (js) and even Ant script cannot replace them.
Can I set scanIntervalSeconds anywhere?
--EDIT--
Main.java
#Configuration
#ComponentScan
#EnableJpaRepositories
#EnableAutoConfiguration
#Import({RepositoryRestMvcConfiguration.class, PersistenceConfig.class, ThymeleafConfig.class})
public class Main {
public static void main(String[] args) throws Exception {
SpringApplication.run(Main.class, args);
}
}
I've run it by right click on class and Debug in IDEA.
How are you launching the app? If you use an IDE with debug mode it should work (except for the locking problem which I believe is Windows OS), or if you launch it with "mvn spring-boot:run", or "gradle bootRun".
I develop using NetBeans 8.0.1.
I fixed the issue of not reloaded static resources in src/main/resources like css (in src/main/resources/resources/css (yes, really twice "resources"!), html-thymeleaf-templates (in src/main/resources/templates) the following way:
My Spring Boot webapp is a JAR project (pom.xml)
Add src/main/resources/application.properties:
spring.template.cache=false
spring.thymeleaf.cache=false
Added custom maven build: Project - Properties - Custom... - Goals...
Execute Goals: spring-boot:run
Set Properties:
jpda.listen=maven (to run it in debug mode)
Env.spring.profiles.active=DEV (optional, but I need it for different SpringConfig-....properties in development, production,...)
Just run the custom maven build for starting the webapp in debug mode. Changes in Thymeleaf-Templates (that are in src/main/resources/templates, eg. index.html (not .xhtml!)) are visible immediately on browser reload.
if you move the css and java script to a folder under
src/main/java/webapp it should work.
for some reason resources under src/main/java/resources didnt seem to get hot deployed when changed.
to fix this as the above post suggested I added
spring.template.cache=false
spring.thymeleaf.cache=false
to Application.properties inside the resources folder.
Note:
I also added this
-javaagent:springloaded-1.2.0.RELEASE.jar -noverify
as a vm runtime argument.

Resources