mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Log useful information on startup
Include the bootstrap version number in the banner and log information such as the host name when starting. Issue: #53030523
This commit is contained in:
parent
7d824a5701
commit
d4b9014b64
@ -41,7 +41,9 @@ abstract class Banner {
|
|||||||
for (String line : BANNER) {
|
for (String line : BANNER) {
|
||||||
printStream.println(line);
|
printStream.println(line);
|
||||||
}
|
}
|
||||||
printStream.println();
|
String version = Banner.class.getPackage().getImplementationVersion();
|
||||||
|
printStream.println(" Spring Bootstrap"
|
||||||
|
+ (version == null ? "" : " (v" + version + ")"));
|
||||||
printStream.println();
|
printStream.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
@ -129,10 +131,16 @@ public class SpringApplication {
|
|||||||
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
|
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
|
||||||
"org.springframework.web.context.ConfigurableWebApplicationContext" };
|
"org.springframework.web.context.ConfigurableWebApplicationContext" };
|
||||||
|
|
||||||
|
private final Log log = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private Object[] sources;
|
private Object[] sources;
|
||||||
|
|
||||||
|
private Class<?> mainApplicationClass;
|
||||||
|
|
||||||
private boolean showBanner = true;
|
private boolean showBanner = true;
|
||||||
|
|
||||||
|
private boolean logStartupInfo = true;
|
||||||
|
|
||||||
private boolean addCommandLineProperties = true;
|
private boolean addCommandLineProperties = true;
|
||||||
|
|
||||||
private ResourceLoader resourceLoader;
|
private ResourceLoader resourceLoader;
|
||||||
@ -193,6 +201,7 @@ public class SpringApplication {
|
|||||||
for (ApplicationContextInitializer<?> initializer : factories) {
|
for (ApplicationContextInitializer<?> initializer : factories) {
|
||||||
this.initializers.add(initializer);
|
this.initializers.add(initializer);
|
||||||
}
|
}
|
||||||
|
this.mainApplicationClass = deduceMainApplicationClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean deduceWebEnvironment() {
|
private boolean deduceWebEnvironment() {
|
||||||
@ -204,6 +213,21 @@ public class SpringApplication {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Class<?> deduceMainApplicationClass() {
|
||||||
|
try {
|
||||||
|
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
|
||||||
|
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||||
|
if ("main".equals(stackTraceElement.getMethodName())) {
|
||||||
|
return Class.forName(stackTraceElement.getClassName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
// Swallow and continue
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the Spring application, creating and refreshing a new
|
* Run the Spring application, creating and refreshing a new
|
||||||
* {@link ApplicationContext}.
|
* {@link ApplicationContext}.
|
||||||
@ -220,6 +244,9 @@ public class SpringApplication {
|
|||||||
if (context instanceof ConfigurableApplicationContext) {
|
if (context instanceof ConfigurableApplicationContext) {
|
||||||
applyInitializers((ConfigurableApplicationContext) context);
|
applyInitializers((ConfigurableApplicationContext) context);
|
||||||
}
|
}
|
||||||
|
if (this.logStartupInfo) {
|
||||||
|
logStartupInfo();
|
||||||
|
}
|
||||||
load(context, this.sources);
|
load(context, this.sources);
|
||||||
refresh(context);
|
refresh(context);
|
||||||
runCommandLineRunners(context, args);
|
runCommandLineRunners(context, args);
|
||||||
@ -251,6 +278,21 @@ public class SpringApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void logStartupInfo() {
|
||||||
|
new StartupInfoLogger(this.mainApplicationClass).log(getApplicationLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link Log} for the application. By default will be deduced.
|
||||||
|
* @return the application log
|
||||||
|
*/
|
||||||
|
protected Log getApplicationLog() {
|
||||||
|
if (this.mainApplicationClass == null) {
|
||||||
|
return this.log;
|
||||||
|
}
|
||||||
|
return LogFactory.getLog(this.mainApplicationClass);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy method used to create the {@link ApplicationContext}. By default this
|
* Strategy method used to create the {@link ApplicationContext}. By default this
|
||||||
* method will respect any explicitly set application context or application context
|
* method will respect any explicitly set application context or application context
|
||||||
@ -454,6 +496,16 @@ public class SpringApplication {
|
|||||||
((AbstractApplicationContext) applicationContext).refresh();
|
((AbstractApplicationContext) applicationContext).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific main application class that will be used as a log source and to
|
||||||
|
* obtain version information. By default the main application class will be deduced.
|
||||||
|
* Can be set to {@code null} if there is no explicit application class.
|
||||||
|
* @param mainApplicationClass the mainApplicationClass to set or {@code null}
|
||||||
|
*/
|
||||||
|
public void setMainApplicationClass(Class<?> mainApplicationClass) {
|
||||||
|
this.mainApplicationClass = mainApplicationClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if this application is running within a web environment. If not specified will
|
* Sets if this application is running within a web environment. If not specified will
|
||||||
* attempt to deduce the environment based on the classpath.
|
* attempt to deduce the environment based on the classpath.
|
||||||
@ -473,6 +525,15 @@ public class SpringApplication {
|
|||||||
this.showBanner = showBanner;
|
this.showBanner = showBanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the application information should be logged when the application starts.
|
||||||
|
* Defaults to {@code true}
|
||||||
|
* @param logStartupInfo if startup info should be logged.
|
||||||
|
*/
|
||||||
|
public void setLogStartupInfo(boolean logStartupInfo) {
|
||||||
|
this.logStartupInfo = logStartupInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if a {@link CommandLinePropertySource} should be added to the application
|
* Sets if a {@link CommandLinePropertySource} should be added to the application
|
||||||
* context in order to expose arguments. Defaults to {@code true}.
|
* context in order to expose arguments. Defaults to {@code true}.
|
||||||
@ -590,6 +651,21 @@ public class SpringApplication {
|
|||||||
return new SpringApplication(sources).run(args);
|
return new SpringApplication(sources).run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper that can be used to run a {@link SpringApplication} from a script
|
||||||
|
* using the specified sources with default settings. This method is useful when
|
||||||
|
* calling this calls from a script environment that will not have a single main
|
||||||
|
* application class.
|
||||||
|
* @param sources the sources to load
|
||||||
|
* @param args the application arguments (usually passed from a Java main method)
|
||||||
|
* @return the running {@link ApplicationContext}
|
||||||
|
*/
|
||||||
|
public static ApplicationContext runFromScript(Object[] sources, String[] args) {
|
||||||
|
SpringApplication application = new SpringApplication(sources);
|
||||||
|
application.setMainApplicationClass(null);
|
||||||
|
return application.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static helper that can be used to exit a {@link SpringApplication} and obtain a
|
* Static helper that can be used to exit a {@link SpringApplication} and obtain a
|
||||||
* code indicating success (0) or otherwise. Does not throw exceptions but should
|
* code indicating success (0) or otherwise. Does not throw exceptions but should
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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.bootstrap;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.JarURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs application information on startup.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
class StartupInfoLogger {
|
||||||
|
|
||||||
|
private final Class<?> sourceClass;
|
||||||
|
|
||||||
|
public StartupInfoLogger(Class<?> sourceClass) {
|
||||||
|
this.sourceClass = sourceClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Log log) {
|
||||||
|
Assert.notNull(log, "Log must not be null");
|
||||||
|
StringBuilder message = new StringBuilder();
|
||||||
|
message.append("Starting ");
|
||||||
|
message.append(getApplicationName());
|
||||||
|
message.append(getVersion());
|
||||||
|
message.append(getOn());
|
||||||
|
message.append(getPid());
|
||||||
|
message.append(getContext());
|
||||||
|
log.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApplicationName() {
|
||||||
|
return (this.sourceClass != null ? ClassUtils.getShortName(this.sourceClass)
|
||||||
|
: "application");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVersion() {
|
||||||
|
return getValue(" v", new Callable<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return StartupInfoLogger.this.sourceClass.getPackage()
|
||||||
|
.getImplementationVersion();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getOn() {
|
||||||
|
return getValue(" on ", new Callable<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return InetAddress.getLocalHost().getHostName();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPid() {
|
||||||
|
return getValue(" with PID ", new Callable<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return System.getProperty("PID");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getContext() {
|
||||||
|
String startedBy = getValue("started by ", new Callable<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return System.getProperty("user.name");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
File codeSourceLocation = getCodeSourceLocation();
|
||||||
|
String path = (codeSourceLocation == null ? "" : codeSourceLocation
|
||||||
|
.getAbsolutePath());
|
||||||
|
if (startedBy == null && codeSourceLocation == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (StringUtils.hasLength(startedBy) && StringUtils.hasLength(path)) {
|
||||||
|
startedBy = " " + startedBy;
|
||||||
|
}
|
||||||
|
return " (" + path + startedBy + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getCodeSourceLocation() {
|
||||||
|
try {
|
||||||
|
ProtectionDomain protectionDomain = (this.sourceClass == null ? getClass()
|
||||||
|
: this.sourceClass).getProtectionDomain();
|
||||||
|
URL location = protectionDomain.getCodeSource().getLocation();
|
||||||
|
File file;
|
||||||
|
URLConnection connection = location.openConnection();
|
||||||
|
if (connection instanceof JarURLConnection) {
|
||||||
|
file = new File(((JarURLConnection) connection).getJarFile().getName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
file = new File(location.getPath());
|
||||||
|
}
|
||||||
|
if (file.exists()) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValue(String prefix, Callable<Object> call) {
|
||||||
|
try {
|
||||||
|
Object value = call.call();
|
||||||
|
if (value != null && StringUtils.hasLength(value.toString())) {
|
||||||
|
return prefix + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Swallow and continue
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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.bootstrap;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link Banner}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class BannerTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void visualBannder() throws Exception {
|
||||||
|
Banner.write(System.out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -131,7 +131,7 @@ public class SpringApplicationRunner {
|
|||||||
// User reflection to load and call Spring
|
// User reflection to load and call Spring
|
||||||
Class<?> application = getContextClassLoader().loadClass(
|
Class<?> application = getContextClassLoader().loadClass(
|
||||||
"org.springframework.bootstrap.SpringApplication");
|
"org.springframework.bootstrap.SpringApplication");
|
||||||
Method method = application.getMethod("run", Object[].class,
|
Method method = application.getMethod("runFromScript", Object[].class,
|
||||||
String[].class);
|
String[].class);
|
||||||
this.applicationContext = method.invoke(null, this.sources,
|
this.applicationContext = method.invoke(null, this.sources,
|
||||||
SpringApplicationRunner.this.args);
|
SpringApplicationRunner.this.args);
|
||||||
|
Loading…
Reference in New Issue
Block a user