Deprecate Bootstrapper

Deprecate the `Bootstrapper` interface entirely and provide a
`BootstrapRegistryInitializer` alternative so that people can migrate.

Unfortunately our previous attempt to fix the typo in the `Bootstrapper`
interface didn't provide us a way to remove the deprecated method
without impacting users. It was also problematic for people who were
implementing `Bootstrapper` rather than using a lambda since they needed
to introduce the deprecated method.

We unfortunately can't see a way to fix the original typo without
introducing a new interface.

Fixes gh-25735
pull/26153/head
Phillip Webb 4 years ago
parent ddf5c9f5d1
commit 35aeae5a4f

@ -0,0 +1,37 @@
/*
* Copyright 2012-2021 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
*
* https://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;
/**
* Callback interface that can be used to initialize a {@link BootstrapRegistry} before it
* is used.
*
* @author Phillip Webb
* @since 2.4.5
* @see SpringApplication#addBootstrapRegistryInitializer(BootstrapRegistryInitializer)
* @see BootstrapRegistry
*/
@FunctionalInterface
public interface BootstrapRegistryInitializer {
/**
* Initialize the given {@link BootstrapRegistry} with any required registrations.
* @param registry the registry to initialize
*/
void initialize(BootstrapRegistry registry);
}

@ -24,7 +24,9 @@ package org.springframework.boot;
* @since 2.4.0
* @see SpringApplication#addBootstrapper(Bootstrapper)
* @see BootstrapRegistry
* @deprecated since 2.4.5 in favor of {@link BootstrapRegistryInitializer}
*/
@Deprecated
public interface Bootstrapper {
/**

@ -236,7 +236,7 @@ public class SpringApplication {
private Map<String, Object> defaultProperties;
private List<Bootstrapper> bootstrappers;
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;
private Set<String> additionalProfiles = Collections.emptySet();
@ -280,12 +280,22 @@ public class SpringApplication {
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
@SuppressWarnings("deprecation")
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
getSpringFactoriesInstances(Bootstrapper.class).stream()
.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
.forEach(initializers::add);
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
@ -349,7 +359,7 @@ public class SpringApplication {
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrappers.forEach((initializer) -> initializer.initialize(bootstrapContext));
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
@ -1054,10 +1064,24 @@ public class SpringApplication {
* {@link BootstrapRegistry}.
* @param bootstrapper the bootstraper
* @since 2.4.0
* @deprecated since 2.4.5 in favor of
* {@link #addBootstrapRegistryInitializer(BootstrapRegistryInitializer)}
*/
@Deprecated
public void addBootstrapper(Bootstrapper bootstrapper) {
Assert.notNull(bootstrapper, "Bootstrapper must not be null");
this.bootstrappers.add(bootstrapper);
this.bootstrapRegistryInitializers.add(bootstrapper::initialize);
}
/**
* Adds {@link BootstrapRegistryInitializer} instances that can be used to initialize
* the {@link BootstrapRegistry}.
* @param bootstrapRegistryInitializer the bootstrap registry initializer to add
* @since 2.4.5
*/
public void addBootstrapRegistryInitializer(BootstrapRegistryInitializer bootstrapRegistryInitializer) {
Assert.notNull(bootstrapRegistryInitializer, "BootstrapRegistryInitializer must not be null");
this.bootstrapRegistryInitializers.addAll(Arrays.asList(bootstrapRegistryInitializer));
}
/**

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@ -31,7 +31,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.ApplicationContextFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.Bootstrapper;
import org.springframework.boot.BootstrapRegistryInitializer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.convert.ApplicationConversionService;
@ -400,17 +400,33 @@ public class SpringApplicationBuilder {
}
/**
* Adds a {@link Bootstrapper} that can be used to initialize the
* {@link BootstrapRegistry}.
* Adds a {@link org.springframework.boot.Bootstrapper} that can be used to initialize
* the {@link BootstrapRegistry}.
* @param bootstrapper the bootstraper
* @return the current builder
* @since 2.4.0
* @deprecated since 2.4.5 in favor of
* {@link #addBootstrapRegistryInitializer(BootstrapRegistryInitializer)}
*/
public SpringApplicationBuilder addBootstrapper(Bootstrapper bootstrapper) {
@Deprecated
public SpringApplicationBuilder addBootstrapper(org.springframework.boot.Bootstrapper bootstrapper) {
this.application.addBootstrapper(bootstrapper);
return this;
}
/**
* Adds {@link BootstrapRegistryInitializer} instances that can be used to initialize
* the {@link BootstrapRegistry}.
* @param bootstrapRegistryInitializer the bootstrap registry initializer to add
* @return the current builder
* @since 2.4.5
*/
public SpringApplicationBuilder addBootstrapRegistryInitializer(
BootstrapRegistryInitializer bootstrapRegistryInitializer) {
this.application.addBootstrapRegistryInitializer(bootstrapRegistryInitializer);
return this;
}
/**
* Flag to control whether the application should be initialized lazily.
* @param lazyInitialization the flag to set. Defaults to false.

@ -1219,10 +1219,10 @@ class SpringApplicationTests {
}
@Test
void addBootstrapper() {
void addBootstrapRegistryInitializer() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addBootstrapper(
application.addBootstrapRegistryInitializer(
(bootstrapContext) -> bootstrapContext.register(String.class, InstanceSupplier.of("boot")));
TestApplicationListener listener = new TestApplicationListener();
application.addListeners(listener);
@ -1235,10 +1235,10 @@ class SpringApplicationTests {
}
@Test
void addBootstrapperCanRegisterBeans() {
void addBootstrapRegistryInitializerCanRegisterBeans() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addBootstrapper((bootstrapContext) -> {
application.addBootstrapRegistryInitializer((bootstrapContext) -> {
bootstrapContext.register(String.class, InstanceSupplier.of("boot"));
bootstrapContext.addCloseListener((event) -> event.getApplicationContext().getBeanFactory()
.registerSingleton("test", event.getBootstrapContext().get(String.class)));
@ -1248,6 +1248,7 @@ class SpringApplicationTests {
}
@Test
@Deprecated
void whenABootstrapperImplementsOnlyTheOldMethodThenItIsCalled() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -1259,6 +1260,7 @@ class SpringApplicationTests {
}
@Test
@Deprecated
void whenABootstrapperImplementsTheOldMethodAndTheNewMethodThenOnlyTheNewMethodIsCalled() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
@ -1743,18 +1745,19 @@ class SpringApplicationTests {
}
@Deprecated
static class OnlyOldMethodTestBootstrapper implements Bootstrapper {
private boolean intitialized;
@Override
@SuppressWarnings("deprecation")
public void intitialize(BootstrapRegistry registry) {
this.intitialized = true;
}
}
@Deprecated
static class BothMethodsTestBootstrapper implements Bootstrapper {
private boolean intitialized;
@ -1762,7 +1765,6 @@ class SpringApplicationTests {
private boolean initialized;
@Override
@SuppressWarnings("deprecation")
public void intitialize(BootstrapRegistry registry) {
this.intitialized = true;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@ -283,6 +283,7 @@ class SpringApplicationBuilderTests {
}
@Test
@Deprecated
void addBootstrapper() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.web(WebApplicationType.NONE).addBootstrapper((context) -> context.addCloseListener(
@ -291,6 +292,15 @@ class SpringApplicationBuilderTests {
assertThat(this.context.getBean("test")).isEqualTo("spring");
}
@Test
void addBootstrapRegistryInitializer() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.web(WebApplicationType.NONE).addBootstrapRegistryInitializer((context) -> context.addCloseListener(
(event) -> event.getApplicationContext().getBeanFactory().registerSingleton("test", "spring")));
this.context = application.run();
assertThat(this.context.getBean("test")).isEqualTo("spring");
}
@Configuration(proxyBeanMethods = false)
static class ExampleConfig {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@ -29,7 +29,7 @@ public class SampleBootstrapRegistryApplication {
// SubversionClient that still has access to data provided in the
// application.properties file
SpringApplication application = new SpringApplication(SampleBootstrapRegistryApplication.class);
application.addBootstrapper(SubversionBootstrap.withCustomClient(MySubversionClient::new));
application.addBootstrapRegistryInitializer(SubversionBootstrap.withCustomClient(MySubversionClient::new));
application.run(args);
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@ -19,10 +19,10 @@ package smoketest.bootstrapregistry.external.svn;
import java.util.function.Function;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.Bootstrapper;
import org.springframework.boot.BootstrapRegistryInitializer;
/**
* Allows the user to register a {@link Bootstrapper} with a custom
* Allows the user to register a {@link BootstrapRegistryInitializer} with a custom
* {@link SubversionClient}.
*
* @author Phillip Webb
@ -33,11 +33,12 @@ public final class SubversionBootstrap {
}
/**
* Return a {@link Bootstrapper} for the given client factory.
* Return a {@link BootstrapRegistryInitializer} for the given client factory.
* @param clientFactory the client factory
* @return a {@link Bootstrapper} instance
* @return a {@link BootstrapRegistryInitializer} instance
*/
public static Bootstrapper withCustomClient(Function<SubversionServerCertificate, SubversionClient> clientFactory) {
public static BootstrapRegistryInitializer withCustomClient(
Function<SubversionServerCertificate, SubversionClient> clientFactory) {
return (registry) -> registry.register(SubversionClient.class,
(bootstrapContext) -> createSubversionClient(bootstrapContext, clientFactory));
}

Loading…
Cancel
Save