commit
91778e9f96
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
|
|
@ -46,6 +46,7 @@ import org.springframework.core.log.LogMessage;
|
|||
* @author Andy Wilkinson
|
||||
* @author Marten Deinum
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
|
||||
|
|
@ -57,46 +58,25 @@ public class H2ConsoleAutoConfiguration {
|
|||
|
||||
private static final Log logger = LogFactory.getLog(H2ConsoleAutoConfiguration.class);
|
||||
|
||||
private final H2ConsoleProperties properties;
|
||||
|
||||
H2ConsoleAutoConfiguration(H2ConsoleProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<JakartaWebServlet> h2Console(H2ConsoleProperties properties,
|
||||
ObjectProvider<DataSource> dataSource) {
|
||||
String path = properties.getPath();
|
||||
public ServletRegistrationBean<JakartaWebServlet> h2Console() {
|
||||
String path = this.properties.getPath();
|
||||
String urlMapping = path + (path.endsWith("/") ? "*" : "/*");
|
||||
ServletRegistrationBean<JakartaWebServlet> registration = new ServletRegistrationBean<>(new JakartaWebServlet(),
|
||||
urlMapping);
|
||||
configureH2ConsoleSettings(registration, properties.getSettings());
|
||||
if (logger.isInfoEnabled()) {
|
||||
withThreadContextClassLoader(getClass().getClassLoader(), () -> logDataSources(dataSource, path));
|
||||
}
|
||||
configureH2ConsoleSettings(registration, this.properties.getSettings());
|
||||
return registration;
|
||||
}
|
||||
|
||||
private void withThreadContextClassLoader(ClassLoader classLoader, Runnable action) {
|
||||
ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
action.run();
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(previous);
|
||||
}
|
||||
}
|
||||
|
||||
private void logDataSources(ObjectProvider<DataSource> dataSource, String path) {
|
||||
List<String> urls = dataSource.orderedStream().map(this::getConnectionUrl).filter(Objects::nonNull).toList();
|
||||
if (!urls.isEmpty()) {
|
||||
logger.info(LogMessage.format("H2 console available at '%s'. %s available at %s", path,
|
||||
(urls.size() > 1) ? "Databases" : "Database", String.join(", ", urls)));
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionUrl(DataSource dataSource) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
return "'" + connection.getMetaData().getURL() + "'";
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
@Bean
|
||||
H2ConsoleLogger h2ConsoleLogger(ObjectProvider<DataSource> dataSource) {
|
||||
return new H2ConsoleLogger(dataSource, this.properties.getPath());
|
||||
}
|
||||
|
||||
private void configureH2ConsoleSettings(ServletRegistrationBean<JakartaWebServlet> registration,
|
||||
|
|
@ -112,4 +92,46 @@ public class H2ConsoleAutoConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
static class H2ConsoleLogger {
|
||||
|
||||
H2ConsoleLogger(ObjectProvider<DataSource> dataSources, String path) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
withThreadContextClassLoader(classLoader, () -> log(getConnectionUrls(dataSources), path));
|
||||
}
|
||||
}
|
||||
|
||||
private void withThreadContextClassLoader(ClassLoader classLoader, Runnable action) {
|
||||
ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
action.run();
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(previous);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getConnectionUrls(ObjectProvider<DataSource> dataSources) {
|
||||
return dataSources.orderedStream().map(this::getConnectionUrl).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
private String getConnectionUrl(DataSource dataSource) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
return "'" + connection.getMetaData().getURL() + "'";
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void log(List<String> urls, String path) {
|
||||
if (!urls.isEmpty()) {
|
||||
logger.info(LogMessage.format("H2 console available at '%s'. %s available at %s", path,
|
||||
(urls.size() > 1) ? "Databases" : "Database", String.join(", ", urls)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
|
|
@ -30,15 +30,20 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBindException;
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
|
@ -51,6 +56,7 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Marten Deinum
|
||||
* @author Stephane Nicoll
|
||||
* @author Shraddha Yeole
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class H2ConsoleAutoConfigurationTests {
|
||||
|
||||
|
|
@ -163,6 +169,22 @@ class H2ConsoleAutoConfigurationTests {
|
|||
.run((context) -> assertThat(context.isRunning()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
void dataSourceIsNotInitializedEarly(CapturedOutput output) {
|
||||
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(H2ConsoleAutoConfiguration.class,
|
||||
ServletWebServerFactoryAutoConfiguration.class))
|
||||
.withUserConfiguration(EarlyInitializationConfiguration.class)
|
||||
.withPropertyValues("spring.h2.console.enabled=true", "server.port=0")
|
||||
.run((context) -> {
|
||||
try (Connection connection = context.getBean(DataSource.class).getConnection()) {
|
||||
assertThat(output).contains("H2 console available at '/h2-console'. Database available at '"
|
||||
+ connection.getMetaData().getURL() + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class FailingDataSourceConfiguration {
|
||||
|
||||
|
|
@ -206,4 +228,15 @@ class H2ConsoleAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class EarlyInitializationConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSource dataSource(ConfigurableApplicationContext applicationContext) {
|
||||
assertThat(applicationContext.getBeanFactory().isConfigurationFrozen()).isTrue();
|
||||
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue