diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java index e45c24ee6ba..7630e045a09 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java @@ -130,7 +130,12 @@ final class ArchitectureRules { } private static ArchRule allPackagesShouldBeFreeOfTangles() { - return SlicesRuleDefinition.slices().matching("(**)").should().beFreeOfCycles(); + return SlicesRuleDefinition.slices() + .matching("(**)") + .should() + .beFreeOfCycles() + .ignoreDependency("org.springframework.boot.env.EnvironmentPostProcessor", + "org.springframework.boot.SpringApplication"); } private static ArchRule allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization() { diff --git a/core/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessor.java b/core/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessor.java new file mode 100644 index 00000000000..08ccbaf1d7a --- /dev/null +++ b/core/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessor.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-present 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.env; + +import org.springframework.boot.bootstrap.BootstrapContext; +import org.springframework.boot.bootstrap.BootstrapRegistry; +import org.springframework.boot.bootstrap.ConfigurableBootstrapContext; +import org.springframework.boot.logging.DeferredLogFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; + +/** + * Allows for customization of the application's {@link Environment} prior to the + * application context being refreshed. + *

+ * EnvironmentPostProcessor implementations have to be registered in + * {@code META-INF/spring.factories}, using the fully qualified name of this class as the + * key. Implementations may implement the {@link org.springframework.core.Ordered Ordered} + * interface or use an {@link org.springframework.core.annotation.Order @Order} annotation + * if they wish to be invoked in specific order. + *

+ * Since Spring Boot 2.4, {@code EnvironmentPostProcessor} implementations may optionally + * take the following constructor parameters: + *

+ * + * @author Andy Wilkinson + * @author Stephane Nicoll + * @since 1.3.0 + * @deprecated since 4.0.0 for removal in 4.2.0 in favor of + * {@link org.springframework.boot.EnvironmentPostProcessor} + */ +@FunctionalInterface +@Deprecated(since = "4.0.0", forRemoval = true) +public interface EnvironmentPostProcessor { + + /** + * Post-process the given {@code environment}. + * @param environment the environment to post-process + * @param application the application to which the environment belongs + */ + void postProcessEnvironment(ConfigurableEnvironment environment, + org.springframework.boot.SpringApplication application); + +} diff --git a/core/spring-boot/src/main/java/org/springframework/boot/support/SpringFactoriesEnvironmentPostProcessorsFactory.java b/core/spring-boot/src/main/java/org/springframework/boot/support/SpringFactoriesEnvironmentPostProcessorsFactory.java index f0bc7310540..ba92a12b5fb 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/support/SpringFactoriesEnvironmentPostProcessorsFactory.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/support/SpringFactoriesEnvironmentPostProcessorsFactory.java @@ -16,13 +16,18 @@ package org.springframework.boot.support; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.springframework.boot.EnvironmentPostProcessor; +import org.springframework.boot.SpringApplication; import org.springframework.boot.bootstrap.BootstrapContext; import org.springframework.boot.bootstrap.BootstrapRegistry; import org.springframework.boot.bootstrap.ConfigurableBootstrapContext; import org.springframework.boot.logging.DeferredLogFactory; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver; @@ -46,7 +51,34 @@ class SpringFactoriesEnvironmentPostProcessorsFactory implements EnvironmentPost argumentResolver = argumentResolver.and(ConfigurableBootstrapContext.class, bootstrapContext); argumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext); argumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext); - return this.loader.load(EnvironmentPostProcessor.class, argumentResolver); + List postProcessors = new ArrayList<>(); + postProcessors.addAll(this.loader.load(EnvironmentPostProcessor.class, argumentResolver)); + postProcessors.addAll(loadDeprecatedPostProcessors()); + AnnotationAwareOrderComparator.sort(postProcessors); + return postProcessors.stream().map(Adapter::apply).collect(Collectors.toCollection(ArrayList::new)); + } + + @SuppressWarnings("removal") + private List loadDeprecatedPostProcessors() { + return this.loader.load(org.springframework.boot.env.EnvironmentPostProcessor.class); + } + + @SuppressWarnings("removal") + record Adapter( + org.springframework.boot.env.EnvironmentPostProcessor postProcessor) implements EnvironmentPostProcessor { + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + this.postProcessor.postProcessEnvironment(environment, application); + } + + static EnvironmentPostProcessor apply(Object source) { + if (source instanceof EnvironmentPostProcessor environmentPostProcessor) { + return environmentPostProcessor; + } + return new Adapter((org.springframework.boot.env.EnvironmentPostProcessor) source); + } + } }