From 3c3e8e6a8bfd45e8f1c3f1df5c7ef66d85d5d5f1 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 11 May 2020 19:48:43 +0200 Subject: [PATCH] Only proxy supported beans in BeanNameAutoProxyCreator Prior to this commit, if a BeanNameAutoProxyCreator was configured with a custom TargetSourceCreator, the TargetSourceCreator was applied to all beans in the ApplicationContext. Thus, the list of supported beanNames was effectively ignored when applying any TargetSourceCreator. Consequently, if a TargetSourceCreator returned a non-null TargetSource for a given bean, the BeanNameAutoProxyCreator proxied the bean even if the bean name had not been configured in the beanNames list. This commit addresses this issue by ensuring that a custom TargetSourceCreator is only applied to beans whose names match the configured beanNames list in a BeanNameAutoProxyCreator. Closes gh-24915 --- .../autoproxy/BeanNameAutoProxyCreator.java | 59 +++++++++++++++---- .../BeanNameAutoProxyCreatorTests.java | 10 ++++ .../BeanNameAutoProxyCreatorTests-context.xml | 24 ++++++++ 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java index cc2b16101dca..8c49d4ff7d28 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 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. @@ -37,6 +37,7 @@ * "interceptorNames" property. * * @author Juergen Hoeller + * @author Sam Brannen * @since 10.10.2003 * @see #setBeanNames * @see #isMatch @@ -46,6 +47,8 @@ @SuppressWarnings("serial") public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator { + private static final String[] NO_ALIASES = new String[0]; + @Nullable private List beanNames; @@ -72,40 +75,70 @@ public void setBeanNames(String... beanNames) { /** - * Identify as bean to proxy if the bean name is in the configured list of names. + * Delegate to {@link AbstractAutoProxyCreator#getCustomTargetSource(Class, String)} + * if the bean name matches one of the names in the configured list of supported + * names, returning {@code null} otherwise. + * @since 5.3 + * @see #setBeanNames(String...) + */ + @Override + protected TargetSource getCustomTargetSource(Class beanClass, String beanName) { + return (isSupportedBeanName(beanClass, beanName) ? + super.getCustomTargetSource(beanClass, beanName) : null); + } + + /** + * Identify as a bean to proxy if the bean name matches one of the names in + * the configured list of supported names. + * @see #setBeanNames(String...) */ @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class beanClass, String beanName, @Nullable TargetSource targetSource) { + return (isSupportedBeanName(beanClass, beanName) ? + PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS : DO_NOT_PROXY); + } + + /** + * Determine if the bean name for the given bean class matches one of the names + * in the configured list of supported names. + * @param beanClass the class of the bean to advise + * @param beanName the name of the bean + * @return {@code true} if the given bean name is supported + * @see #setBeanNames(String...) + */ + private boolean isSupportedBeanName(Class beanClass, String beanName) { if (this.beanNames != null) { + boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass); for (String mappedName : this.beanNames) { - if (FactoryBean.class.isAssignableFrom(beanClass)) { + if (isFactoryBean) { if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { continue; } mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } if (isMatch(beanName, mappedName)) { - return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; + return true; } - BeanFactory beanFactory = getBeanFactory(); - if (beanFactory != null) { - String[] aliases = beanFactory.getAliases(beanName); - for (String alias : aliases) { - if (isMatch(alias, mappedName)) { - return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; - } + } + + BeanFactory beanFactory = getBeanFactory(); + String[] aliases = (beanFactory != null ? beanFactory.getAliases(beanName) : NO_ALIASES); + for (String alias : aliases) { + for (String mappedName : this.beanNames) { + if (isMatch(alias, mappedName)) { + return true; } } } } - return DO_NOT_PROXY; + return false; } /** - * Return if the given bean name matches the mapped name. + * Determine if the given bean name matches the mapped name. *

The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, * as well as direct equality. Can be overridden in subclasses. * @param beanName the bean name to check diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java index 4e03a4a2db08..153080c0ee13 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java @@ -155,6 +155,16 @@ void withFrozenProxy() { assertThat(((Advised)testBean).isFrozen()).isTrue(); } + @Test + void customTargetSourceCreatorsApplyOnlyToConfiguredBeanNames() { + ITestBean lazy1 = beanFactory.getBean("lazy1", ITestBean.class); + ITestBean alias1 = beanFactory.getBean("lazy1alias", ITestBean.class); + ITestBean lazy2 = beanFactory.getBean("lazy2", ITestBean.class); + assertThat(AopUtils.isAopProxy(lazy1)).isTrue(); + assertThat(AopUtils.isAopProxy(alias1)).isTrue(); + assertThat(AopUtils.isAopProxy(lazy2)).isFalse(); + } + private void jdkAssertions(ITestBean tb, int nopInterceptorCount) { NopInterceptor nop = (NopInterceptor) beanFactory.getBean("nopInterceptor"); diff --git a/spring-context/src/test/resources/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests-context.xml b/spring-context/src/test/resources/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests-context.xml index 15e9b0e9cd55..6327f5ecba09 100644 --- a/spring-context/src/test/resources/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests-context.xml +++ b/spring-context/src/test/resources/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests-context.xml @@ -104,4 +104,28 @@ + + + + + + + + + + + + + + + + + + + + + + + +