Reputation: 703
Edit
Alright, so it looks like the SpringBootServletInitializer
isn't detected because it's inside a JAR in the EAR, not the WAR. What I did was make a new module and included it in my WAR. This contained a META-INF directory with a services folder. That services folder has a single file (javax.servlet.ServletContainerInitializer
) with the contents org.springframework.web.SpringServletContainerInitializer
. This then tries to deploy the WAR, but fails with the following:
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: JBAS018104: Deployment error processing SCI for jar: test-1.0.0-SNAPSHOT.jar
at org.jboss.as.web.deployment.ServletContainerInitializerDeploymentProcessor.loadSci(ServletContainerInitializerDeploymentProcessor.java:202)
... 7 more
Caused by: java.lang.ClassCastException: org.springframework.web.SpringServletContainerInitializer cannot be cast to javax.servlet.ServletContainerInitializer
at org.jboss.as.web.deployment.ServletContainerInitializerDeploymentProcessor.loadSci(ServletContainerInitializerDeploymentProcessor.java:194)
... 7 more
Again, it looks like the Servlet API is conflicting with another - but there's only the one on the classpath from what I can tell (and I even scoped it as provided for this test).
Original
Currently I'm having a few issues deploying a Spring-Boot (1.3.2.RELEASE) EAR in JBoss 6.4 EAP. The EAR file simply wraps a skinny WAR and all the JARs in a /lib folder.
I had previously made the changes required to deploy the WAR file, but we've unfortunately run into the requirement that the deployment has to be an EAR.
Deploying as a WAR
To deploy the application as a WAR, I changed the following:
pom.xml
<!-- JavaEE 7 for JPA 2.1 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<!-- Exclude Tomcat -->
<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>
<!-- Include Servlet 3 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
jboss-deployment-structure.xml
<?xml version="1.0"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclude-subsystems>
<subsystem name="jpa"/>
</exclude-subsystems>
<exclusions>
<module name="javaee.api"/>
</exclusions>
</deployment>
</jboss-deployment-structure>
Application.java
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
private static final Class<Application> APPLICATION_CLASS = Application.class;
public static void main(String[] args) {
SpringApplication.run(APPLICATION_CLASS, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(APPLICATION_CLASS);
}
}
These changes worked fine, and I could now deploy the WAR to JBoss 6.4.
Deploying as an EAR
This is where the trouble starts. I created a new module to build the EAR file using the maven-ear-plugin:
<build>
<finalName>my-application</finalName>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<version>6</version>
<skinnyWars>true</skinnyWars>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<fileNameMapping>no-version</fileNameMapping>
<modules>
<webModule>
<groupId>com.test.app</groupId>
<artifactId>my-application</artifactId>
<bundleFileName>my-application.war</bundleFileName>
<context-root>/my-app</context-root>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
I also added the jboss-deployment-structure.xml
under /src/main/application/META-INF, so that it would be included in the EAR (it needs to be at the highest level). Trying to deploy this results in "success", but JBoss never tries to deploy the WAR inside the EAR. It seems that a web.xml is needed.
So looking at the docs, it seems that I need to define a web.xml like follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.test.app.Application</param-value>
</context-param>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Now there is some additional configuration if I want to drop to Servlet 2.5 - but I don't want to do this.
Attempting to deploy this results in the following exception:
10:29:40,586 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/company-api-entity]] (ServerService Thread Pool -- 56) JBWEB000289: Servlet appServlet threw load() exception: java.lang.ClassCastException: org.springframework.web.servlet.DispatcherServlet cannot be cast to javax.servlet.Servlet
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1100) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3593) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
at org.apache.catalina.core.StandardContext.start(StandardContext.java:3802) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:163) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:61) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:96) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [rt.jar:1.8.0_45]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [rt.jar:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_45]
at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_45]
at org.jboss.threads.JBossThread.run(JBossThread.java:122)
This would seem that there's a mismatch in the servlet versions being loaded, but I can't seem to verify that it is (or exclude it). I've tried setting the scope to provided (so the JBoss version takes over), but this results in the following error:
11:18:47,141 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/company-api-entity]] (ServerService Thread Pool -- 52) JBWEB000289: Servlet appServlet threw load() exception: java.util.MissingResourceException: Can't find bundle for base name javax.servlet.LocalStrings, locale en_IE
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1564) [rt.jar:1.8.0_45]
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1387) [rt.jar:1.8.0_45]
at java.util.ResourceBundle.getBundle(ResourceBundle.java:773) [rt.jar:1.8.0_45]
at javax.servlet.GenericServlet.<clinit>(GenericServlet.java:95) [jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar:1.0.2.Final-redhat-2]
Clearly it's using the JBoss 3.0 servlet spec, but it would seem the actual servlet 3.0 JAR is missing.
Is there something that I'm missing? Does the WAR actually need a web.xml, or is there some other way? Is what I'm trying even possible?
Any help would be greatly appreciated.
Upvotes: 4
Views: 4875
Reputation: 703
Fixed the issue. Starting from the WAR deployment, I made an additional EAR module. I shouldn't have used a skinnyWar, and instead left all the JARs inside the WAR. This allows Spring to properly bootstrap the Spring Boot servlet.
This has the following configuration:
<build>
<finalName>my-application</finalName>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<modules>
<webModule>
<groupId>com.test.app</groupId>
<artifactId>my-application</artifactId>
<bundleFileName>my-application.war</bundleFileName>
<context-root>/my-app</context-root>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
I also made sure that there were no compile scoped dependencies in my parent module (the root pom).
I then made sure to have the following file in my EAR:
src/main/application/META-INF/jboss-deployment-structure.xml
While this was in my WAR, the main problem I had was that I was still using <deployment>
instead of <sub-deployment>
<?xml version="1.0"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<sub-deployment name="my-application.war">
<exclude-subsystems>
<subsystem name="jpa"/>
</exclude-subsystems>
<exclusions>
<module name="javaee.api"/>
</exclusions>
</sub-deployment>
</jboss-deployment-structure>
This properly excludes the javaee.api
module and the jpa
subsystem.
After this, the EAR deployed correctly to JBoss.
Upvotes: 1