diff --git a/README.adoc b/README.adoc index 241d3b25503..3897ad11168 100644 --- a/README.adoc +++ b/README.adoc @@ -61,7 +61,7 @@ Having trouble with Spring Boot, We'd like to help! * Check the {docs}/htmlsingle/[reference documentation], especially the {docs}/htmlsingle/#howto[How-to's] -- they provide solutions to the most common questions. -* Learn the Spring basics -- Spring Boot is builds on many other Spring projects, check +* Learn the Spring basics -- Spring Boot builds on many other Spring projects, check the http://spring.io[spring.io] web-site for a wealth of reference documentation. If you are just starting out with Spring, try one of the http://spring.io/guides[guides]. * Ask a questions - we monitor http://stackoverflow.com[stackoverflow.com] for questions diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationLauncher.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationLauncher.java new file mode 100644 index 00000000000..44fec71cad6 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationLauncher.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.app; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * A launcher for {@code SpringApplication}. Uses reflection to allow the launching code + * to exist in a separate ClassLoader from the application code. + * + * @author Andy Wilkinson + * @since 1.2.0 + */ +public class SpringApplicationLauncher { + + private static final String SPRING_APPLICATION_CLASS = "org.springframework.boot.SpringApplication"; + + private final ClassLoader classLoader; + + /** + * Creates a new launcher that will use the given {@code classLoader} to load + * {@code SpringApplication}. + * + * @param classLoader the {@code ClassLoader} to use + */ + public SpringApplicationLauncher(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Launches the application created using the given {@code sources}. The application + * is launched with the given {@code args}. + * + * @param sources The sources for the application + * @param args The args for the application + * @return The application's {@code ApplicationContext} + * @throws Exception if the launch fails + */ + public Object launch(Object[] sources, String[] args) throws Exception { + Map defaultProperties = new HashMap(); + defaultProperties.put("spring.groovy.template.check-template-location", "false"); + + Class applicationClass = this.classLoader.loadClass(SPRING_APPLICATION_CLASS); + Object application = applicationClass.getConstructor(Object[].class).newInstance( + (Object) sources); + applicationClass.getMethod("setDefaultProperties", Map.class).invoke(application, + defaultProperties); + Method method = applicationClass.getMethod("run", String[].class); + return method.invoke(application, (Object) args); + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java index c122c6ca4a7..8931ea06284 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java @@ -42,6 +42,7 @@ import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.transform.ASTTransformation; +import org.springframework.boot.cli.app.SpringApplicationLauncher; import org.springframework.boot.cli.command.Command; import org.springframework.boot.cli.command.OptionParsingCommand; import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource; @@ -207,6 +208,7 @@ public class JarCommand extends OptionParsingCommand { private void addCliClasses(JarWriter writer) throws IOException { addClass(writer, PackagedSpringApplicationLauncher.class); + addClass(writer, SpringApplicationLauncher.class); Resource[] resources = new PathMatchingResourcePatternResolver() .getResources("org/springframework/boot/groovy/**"); for (Resource resource : resources) { diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/run/SpringApplicationRunner.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/run/SpringApplicationRunner.java index 4720e5a587a..9d9f6be2bdc 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/run/SpringApplicationRunner.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/run/SpringApplicationRunner.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import org.springframework.boot.cli.app.SpringApplicationLauncher; import org.springframework.boot.cli.compiler.GroovyCompiler; import org.springframework.boot.cli.util.ResourceUtils; @@ -144,12 +145,8 @@ public class SpringApplicationRunner { @Override public void run() { try { - // User reflection to load and call Spring - Class application = getContextClassLoader().loadClass( - "org.springframework.boot.SpringApplication"); - Method method = application.getMethod("run", Object[].class, - String[].class); - this.applicationContext = method.invoke(null, this.compiledSources, + this.applicationContext = new SpringApplicationLauncher( + getContextClassLoader()).launch(this.compiledSources, SpringApplicationRunner.this.args); } catch (Exception ex) { diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java index c78ccfe528c..10f6a817a8d 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java @@ -16,13 +16,14 @@ package org.springframework.boot.cli.jar; -import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.jar.Attributes; import java.util.jar.Manifest; +import org.springframework.boot.cli.app.SpringApplicationLauncher; + /** * A launcher for a CLI application that has been compiled and packaged as a jar file. * @@ -35,14 +36,10 @@ public class PackagedSpringApplicationLauncher { public static final String START_CLASS_ENTRY = "Start-Class"; - private static final String SPRING_APPLICATION_CLASS = "org.springframework.boot.SpringApplication"; - private void run(String[] args) throws Exception { URLClassLoader classLoader = (URLClassLoader) Thread.currentThread() .getContextClassLoader(); - Class application = classLoader.loadClass(SPRING_APPLICATION_CLASS); - Method method = application.getMethod("run", Object[].class, String[].class); - method.invoke(null, getSources(classLoader), args); + new SpringApplicationLauncher(classLoader).launch(getSources(classLoader), args); } private Object[] getSources(URLClassLoader classLoader) throws Exception {