Spring Boot的嵌入式tomcat非常方便,无论是开发还是部署。
但是,如果需要添加另一个(第三方) WAR文件(例如,GeoServer),该怎么办?
也许以下是正常的过程:
但是,如果可以进行以下配置,那就太好了。
将Spring boot应用程序构建为独立的Jar,其中包括嵌入式Tomcat.
同时包含Spring boot应用程序内容和另一个WAR内容的文件夹中
怎么做呢?
更新
当spring boot应用程序由fat jar(=可执行jar)组成时,答案中的代码是不够的。修订后的版本如下:
@Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
try {
Context context = tomcat.addWebapp("/foo", "/path/to/foo.war");
WebappLoader loader =
new WebappLoader(Thread.currentThread().getContextClassLoader());
context.setLoader(loader);
} catch (ServletException ex) {
throw new IllegalStateException("Failed to add webapp", ex);
}
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
由于fat jar中的jar文件不能由系统类加载器加载,因此必须指定显式的父类加载器。否则,附加的WAR将无法在添加了WAR的spring引导应用程序的fat jar中加载库jar。
发布于 2015-07-13 16:46:19
您可以使用Tomcat.addWebapp
将war文件添加到嵌入式Tomcat。正如其javadoc所说,它“相当于将一个web应用程序添加到Tomcat的web应用程序目录中”。要在Spring Boot中使用此接口,您需要使用一个自定义的TomcatEmbeddedServletContainerFactory
子类:
@Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
// Ensure that the webapps directory exists
new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
try {
Context context = tomcat.addWebapp("/foo", "/path/to/foo.war");
// Allow the webapp to load classes from your fat jar
context.setParentClassLoader(getClass().getClassLoader());
} catch (ServletException ex) {
throw new IllegalStateException("Failed to add webapp", ex);
}
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
发布于 2019-09-17 22:02:22
公认的答案包括Spring Boot 1.x。所提到的类在Spring Boot2.x中不再存在。使用版本2时,您需要使用不同的版本:
@Bean
@ConditionalOnProperty(name = "external.war.file")
public TomcatServletWebServerFactory servletContainerFactory(@Value("${external.war.file}") String path,
@Value("${external.war.context:}") String contextPath) {
return new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
Context context = tomcat.addWebapp(contextPath, path);
context.setParentClassLoader(getClass().getClassLoader());
return super.getTomcatWebServer(tomcat);
}
};
}
另外,Spring boot嵌入式Tomcat在默认情况下不包含JSP的依赖项。如果您在外部war中使用JSP,则需要包含它们。
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
更新:我已经编写了a more detailed blog post on how to set this up for both Spring Boot 1 and 2。
发布于 2019-06-26 07:43:55
对于Spring Boot2,我花了一段时间才弄明白这一点,因为没有一个答案对我完全有效。我最终想出了这个(仅供参考,我已经打开了SSL ):WarRun.java,下面有Gradle依赖项来让它工作。
它提供了什么:
带有上下文路径/ at https://localhost:8070的嵌入式tomcat
https://localhost:8070/sample上的sample.war
https://localhost:8070/yo上的SampleWebApp.war
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Properties;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ClassPathResource;
@ComponentScan({ "com.towianski.controllers" })
@SpringBootApplication
@Profile("server")
public class WarRun extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WarRun.class).web( WebApplicationType.SERVLET );
}
public static void main(String[] args) {
SpringApplication app = new SpringApplication(WarRun.class);
System.out.println( "Entered WarRun.main");
String loggingFile = "";
String dir = "";
for ( int i = 0; i < args.length; i++ )
{
// logger.info( "** args [" + i + "] =" + args[i] + "=" );
System.out.println( "** args [" + i + "] =" + args[i] + "=" );
if ( args[i].toLowerCase().startsWith( "-dir" ) )
{
dir = args[i].substring( "-dir=".length() );
}
else if ( args[i].toLowerCase().startsWith( "--logging.file" ) )
{
loggingFile = args[i].substring( "--logging.file=".length() );
stdOutFilePropertyChange( loggingFile );
stdErrFilePropertyChange( loggingFile );
}
}
Properties properties = new Properties();
// properties.setProperty( "spring.resources.static-locations",
// "classpath:/home/stan/Downloads" );
properties.setProperty( "server.port", "8070" );
// System.setProperty("server.servlet.context-path", "/prop"); <--- Will set embedded Spring Boot Tomcat context path
properties.setProperty( "spring.security.user.name", "stan" );
properties.setProperty( "spring.security.user.password", "stan" );
System.out.println( "Entered WarRun.main after set properties");
app.setDefaultProperties(properties);
System.out.println( "Entered WarRun.main after call set props. before app.run");
app.run(args);
System.out.println( "Entered WarRun.main after app.run()");
}
@Bean
public ServletWebServerFactory servletContainer() {
return new TomcatServletWebServerFactory() {
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
System.out.println( "tomcat.getServer().getCatalinaBase() =" + tomcat.getServer().getCatalinaBase() + "=" );
new File(tomcat.getServer().getCatalinaBase(), "/webapps").mkdirs();
// try {
// Files.copy( (new File( "/home/stan/Downloads/sample.war" ) ).toPath(), (new File( tomcat.getServer().getCatalinaBase() +"/webapp/sample.war") ).toPath());
// } catch (IOException ex) {
// Logger.getLogger(WarRun.class.getName()).log(Level.SEVERE, null, ex);
// }
try {
System.out.println( "Entered ServletWebServerFactory servletContainer()");
Context context2 = tomcat.addWebapp("/sample", new ClassPathResource("file:/home/stan/Downloads/sample.war").getFile().toString());
Context context3 = tomcat.addWebapp("/yo", new ClassPathResource("file:/home/stan/Downloads/SampleWebApp.war").getFile().toString());
// Context context = tomcat.addWebapp("/what", new ClassPathResource( "file:" + tomcat.getServer().getCatalinaBase() +"/webapps/sample.war" ).getFile().toString() );
context2.setParentClassLoader(getClass().getClassLoader());
context3.setParentClassLoader(getClass().getClassLoader());
// also works but above seems better
// WebappLoader loader2 = new WebappLoader(Thread.currentThread().getContextClassLoader());
// WebappLoader loader3 = new WebappLoader(Thread.currentThread().getContextClassLoader());
// context2.setLoader(loader2);
// context3.setLoader(loader3);
} catch (IOException ex) {
ex.printStackTrace();
}
return super.getTomcatWebServer(tomcat);
}
};
}
}
Gradle:
apply plugin: 'war'
war {
enabled = true
}
. . . .
dependencies {
compile("org.springframework.boot:spring-boot-starter:2.1.6.RELEASE")
compile("org.springframework.boot:spring-boot-starter-web:2.1.6.RELEASE")
compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.0.21'
compile("org.springframework.boot:spring-boot-starter-security:2.1.6.RELEASE")
compile 'org.apache.httpcomponents:httpclient:4.5.7'
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.6'
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.jcraft:jsch:0.1.55'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
https://stackoverflow.com/questions/31374726
复制相似问题