Move AOP auto-configuration into spring-boot-autoconfigure

This commit is contained in:
Andy Wilkinson
2025-04-29 10:19:49 +01:00
committed by Phillip Webb
parent a527e028a7
commit 5b12959189
9 changed files with 15 additions and 13 deletions

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2012-2025 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.autoconfigure.aop;
import org.aspectj.weaver.Advice;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} for Spring's AOP support. Equivalent to enabling
* {@link EnableAspectJAutoProxy @EnableAspectJAutoProxy} in your configuration.
* <p>
* The configuration will not be activated if {@literal spring.aop.auto=false}. The
* {@literal proxyTargetClass} attribute will be {@literal true}, by default, but can be
* overridden by specifying {@literal spring.aop.proxy-target-class=false}.
*
* @author Dave Syer
* @author Josh Long
* @since 1.0.0
* @see EnableAspectJAutoProxy
*/
@AutoConfiguration
@ConditionalOnBooleanProperty(name = "spring.aop.auto", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
static class ClassProxyingConfiguration {
@Bean
static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
return (beanFactory) -> {
if (beanFactory instanceof BeanDefinitionRegistry registry) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
};
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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
*
* 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.
*/
/**
* Auto-configuration for Spring AOP.
*/
package org.springframework.boot.autoconfigure.aop;

View File

@@ -287,6 +287,18 @@
"level": "error"
}
},
{
"name": "spring.aop.auto",
"type": "java.lang.Boolean",
"description": "Add @EnableAspectJAutoProxy.",
"defaultValue": true
},
{
"name": "spring.aop.proxy-target-class",
"type": "java.lang.Boolean",
"description": "Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).",
"defaultValue": true
},
{
"name": "spring.application.admin.enabled",
"type": "java.lang.Boolean",

View File

@@ -1,4 +1,5 @@
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration

View File

@@ -0,0 +1,190 @@
/*
* Copyright 2012-2023 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.autoconfigure.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.weaver.Advice;
import org.junit.jupiter.api.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AopAutoConfiguration}.
*
* @author Eberhard Wolff
* @author Stephane Nicoll
*/
class AopAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AopAutoConfiguration.class));
@Test
void aopDisabled() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.aop.auto:false")
.run((context) -> {
TestAspect aspect = context.getBean(TestAspect.class);
assertThat(aspect.isCalled()).isFalse();
TestBean bean = context.getBean(TestBean.class);
bean.foo();
assertThat(aspect.isCalled()).isFalse();
});
}
@Test
void aopWithDefaultSettings() {
this.contextRunner.withUserConfiguration(TestConfiguration.class).run(proxyTargetClassEnabled());
}
@Test
void aopWithEnabledProxyTargetClass() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.aop.proxy-target-class:true")
.run(proxyTargetClassEnabled());
}
@Test
void aopWithDisabledProxyTargetClass() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.aop.proxy-target-class:false")
.run(proxyTargetClassDisabled());
}
@Test
void customConfigurationWithProxyTargetClassDefaultDoesNotDisableProxying() {
this.contextRunner.withUserConfiguration(CustomTestConfiguration.class).run(proxyTargetClassEnabled());
}
@Test
void whenGlobalMethodSecurityIsEnabledAndAspectJIsNotAvailableThenClassProxyingIsStillUsedByDefault() {
this.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class))
.withUserConfiguration(ExampleController.class, EnableGlobalMethodSecurityConfiguration.class)
.run((context) -> assertThat(context).getBean(ExampleController.class).matches(AopUtils::isCglibProxy));
}
private ContextConsumer<AssertableApplicationContext> proxyTargetClassEnabled() {
return (context) -> {
TestAspect aspect = context.getBean(TestAspect.class);
assertThat(aspect.isCalled()).isFalse();
TestBean bean = context.getBean(TestBean.class);
bean.foo();
assertThat(aspect.isCalled()).isTrue();
};
}
private ContextConsumer<AssertableApplicationContext> proxyTargetClassDisabled() {
return (context) -> {
TestAspect aspect = context.getBean(TestAspect.class);
assertThat(aspect.isCalled()).isFalse();
TestInterface bean = context.getBean(TestInterface.class);
bean.foo();
assertThat(aspect.isCalled()).isTrue();
assertThat(context).doesNotHaveBean(TestBean.class);
};
}
@EnableAspectJAutoProxy
@Configuration(proxyBeanMethods = false)
@Import(TestConfiguration.class)
static class CustomTestConfiguration {
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
@Bean
TestAspect aspect() {
return new TestAspect();
}
@Bean
TestInterface bean() {
return new TestBean();
}
}
static class TestBean implements TestInterface {
@Override
public void foo() {
}
}
@Aspect
static class TestAspect {
private boolean called;
boolean isCalled() {
return this.called;
}
@Before("execution(* foo(..))")
void before() {
this.called = true;
}
}
interface TestInterface {
void foo();
}
@EnableMethodSecurity(prePostEnabled = true)
@Configuration(proxyBeanMethods = false)
static class EnableGlobalMethodSecurityConfiguration {
}
public static class ExampleController implements TestInterface {
@RequestMapping("/test")
@PreAuthorize("true")
String demo() {
return "test";
}
@Override
public void foo() {
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2012-2023 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.autoconfigure.aop;
import org.junit.jupiter.api.Test;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AopAutoConfiguration} without AspectJ.
*
* @author Andy Wilkinson
*/
@ClassPathExclusions("aspectjweaver*.jar")
class NonAspectJAopAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AopAutoConfiguration.class));
@Test
void whenAspectJIsAbsentAndProxyTargetClassIsEnabledProxyCreatorBeanIsDefined() {
this.contextRunner.run((context) -> {
BeanDefinition autoProxyCreator = context.getBeanFactory()
.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
assertThat(autoProxyCreator.getPropertyValues().get("proxyTargetClass")).isEqualTo(Boolean.TRUE);
});
}
@Test
void whenAspectJIsAbsentAndProxyTargetClassIsDisabledNoProxyCreatorBeanIsDefined() {
this.contextRunner.withPropertyValues("spring.aop.proxy-target-class:false")
.run((context) -> assertThat(context).doesNotHaveBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
}
}