diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfiguration.java index 8b2c5b6c85..bdc9d6c86b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -22,8 +22,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.Order; /** @@ -54,4 +56,29 @@ public @interface ManagementContextConfiguration { */ ManagementContextType value() default ManagementContextType.ANY; + /** + * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce + * bean lifecycle behavior, e.g. to return shared singleton bean instances even in + * case of direct {@code @Bean} method calls in user code. This feature requires + * method interception, implemented through a runtime-generated CGLIB subclass which + * comes with limitations such as the configuration class and its methods not being + * allowed to declare {@code final}. + *
+ * The default is {@code true}, allowing for 'inter-bean references' within the + * configuration class as well as for external calls to this configuration's + * {@code @Bean} methods, e.g. from another configuration class. If this is not needed + * since each of this particular configuration's {@code @Bean} methods is + * self-contained and designed as a plain factory method for container use, switch + * this flag to {@code false} in order to avoid CGLIB subclass processing. + *
+ * Turning off bean method interception effectively processes {@code @Bean} methods + * individually like when declared on non-{@code @Configuration} classes, a.k.a. + * "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally + * equivalent to removing the {@code @Configuration} stereotype. + * @return whether to proxy {@code @Bean} methods + * @since 2.2 + */ + @AliasFor(annotation = Configuration.class) + boolean proxyBeanMethods() default true; + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfigurationTests.java new file mode 100644 index 0000000000..82afa9e1a0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfigurationTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2019 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.actuate.autoconfigure.web; + +import org.junit.Test; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationAttributes; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ManagementContextConfiguration @ManagementContextConfiguration}. + * + * @author Andy Wilkinson + */ +public class ManagementContextConfigurationTests { + + @Test + public void proxyBeanMethodsIsEnabledByDefault() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes( + DefaultManagementContextConfiguration.class, Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(true); + } + + @Test + public void proxyBeanMethodsCanBeDisabled() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes( + NoBeanMethodProxyingManagementContextConfiguration.class, + Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(false); + } + + @ManagementContextConfiguration + private static class DefaultManagementContextConfiguration { + + } + + @ManagementContextConfiguration(proxyBeanMethods = false) + private static class NoBeanMethodProxyingManagementContextConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java index cd61b7321d..82a9a6aaa4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -41,6 +41,7 @@ import org.springframework.core.annotation.AliasFor; * * @author Phillip Webb * @author Stephane Nicoll + * @author Andy Wilkinson * @since 1.2.0 */ @Target(ElementType.TYPE) @@ -91,4 +92,29 @@ public @interface SpringBootApplication { @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class>[] scanBasePackageClasses() default {}; + /** + * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce + * bean lifecycle behavior, e.g. to return shared singleton bean instances even in + * case of direct {@code @Bean} method calls in user code. This feature requires + * method interception, implemented through a runtime-generated CGLIB subclass which + * comes with limitations such as the configuration class and its methods not being + * allowed to declare {@code final}. + *
+ * The default is {@code true}, allowing for 'inter-bean references' within the + * configuration class as well as for external calls to this configuration's + * {@code @Bean} methods, e.g. from another configuration class. If this is not needed + * since each of this particular configuration's {@code @Bean} methods is + * self-contained and designed as a plain factory method for container use, switch + * this flag to {@code false} in order to avoid CGLIB subclass processing. + *
+ * Turning off bean method interception effectively processes {@code @Bean} methods + * individually like when declared on non-{@code @Configuration} classes, a.k.a. + * "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally + * equivalent to removing the {@code @Configuration} stereotype. + * @since 2.2 + * @return whether to proxy {@code @Bean} methods + */ + @AliasFor(annotation = Configuration.class) + boolean proxyBeanMethods() default true; + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SpringBootApplicationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SpringBootApplicationTests.java new file mode 100644 index 0000000000..49098e3862 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SpringBootApplicationTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2019 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.autoconfigure; + +import org.junit.Test; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationAttributes; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringBootApplication @SpringBootApplication}. + * + * @author Andy Wilkinson + */ +public class SpringBootApplicationTests { + + @Test + public void proxyBeanMethodsIsEnabledByDefault() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes(DefaultSpringBootApplication.class, + Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(true); + } + + @Test + public void proxyBeanMethodsCanBeDisabled() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes( + NoBeanMethodProxyingSpringBootApplication.class, + Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(false); + } + + @SpringBootApplication + private static class DefaultSpringBootApplication { + + } + + @SpringBootApplication(proxyBeanMethods = false) + private static class NoBeanMethodProxyingSpringBootApplication { + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootConfiguration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootConfiguration.java index e0d2df13fe..1e9bc6359f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootConfiguration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -22,7 +22,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AliasFor; /** * Indicates that a class provides Spring Boot application @@ -35,6 +37,7 @@ import org.springframework.context.annotation.Configuration; * {@code @SpringBootApplication}. * * @author Phillip Webb + * @author Andy Wilkinson * @since 1.4.0 */ @Target(ElementType.TYPE) @@ -43,4 +46,29 @@ import org.springframework.context.annotation.Configuration; @Configuration public @interface SpringBootConfiguration { + /** + * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce + * bean lifecycle behavior, e.g. to return shared singleton bean instances even in + * case of direct {@code @Bean} method calls in user code. This feature requires + * method interception, implemented through a runtime-generated CGLIB subclass which + * comes with limitations such as the configuration class and its methods not being + * allowed to declare {@code final}. + *
+ * The default is {@code true}, allowing for 'inter-bean references' within the + * configuration class as well as for external calls to this configuration's + * {@code @Bean} methods, e.g. from another configuration class. If this is not needed + * since each of this particular configuration's {@code @Bean} methods is + * self-contained and designed as a plain factory method for container use, switch + * this flag to {@code false} in order to avoid CGLIB subclass processing. + *
+ * Turning off bean method interception effectively processes {@code @Bean} methods + * individually like when declared on non-{@code @Configuration} classes, a.k.a. + * "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally + * equivalent to removing the {@code @Configuration} stereotype. + * @return whether to proxy {@code @Bean} methods + * @since 2.2 + */ + @AliasFor(annotation = Configuration.class) + boolean proxyBeanMethods() default true; + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringBootConfigurationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringBootConfigurationTests.java new file mode 100644 index 0000000000..9d82a79273 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringBootConfigurationTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2019 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; + +import org.junit.Test; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationAttributes; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringBootConfiguration @SpringBootConfiguration}. + * + * @author Andy Wilkinson + */ +public class SpringBootConfigurationTests { + + @Test + public void proxyBeanMethodsIsEnabledByDefault() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes(DefaultSpringBootConfiguration.class, + Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(true); + } + + @Test + public void proxyBeanMethodsCanBeDisabled() { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes( + NoBeanMethodProxyingSpringBootConfiguration.class, + Configuration.class); + assertThat(attributes.get("proxyBeanMethods")).isEqualTo(false); + } + + @SpringBootConfiguration + private static class DefaultSpringBootConfiguration { + + } + + @SpringBootConfiguration(proxyBeanMethods = false) + private static class NoBeanMethodProxyingSpringBootConfiguration { + + } + +}