瀏覽代碼

#3912 lazyBean method respects @Primary annotation

Karl Goffin 6 年之前
父節點
當前提交
db5e54266c

+ 25 - 11
config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java

@@ -15,21 +15,15 @@
  */
 package org.springframework.security.config.annotation.authentication.configuration;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.springframework.aop.framework.ProxyFactoryBean;
 import org.springframework.aop.target.LazyInitTargetSource;
 import org.springframework.beans.factory.BeanFactoryUtils;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
@@ -49,6 +43,13 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.util.Assert;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
 /**
  * Exports the authentication {@link Configuration}
  *
@@ -151,10 +152,23 @@ public class AuthenticationConfiguration {
 		if (beanNamesForType.length == 0) {
 			return null;
 		}
-		Assert.isTrue(beanNamesForType.length == 1,
-				() -> "Expecting to only find a single bean for type " + interfaceName
-						+ ", but found " + Arrays.asList(beanNamesForType));
-		lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
+		String beanName;
+		if (beanNamesForType.length > 1) {
+			List<String> primaryBeanNames = Arrays.stream(beanNamesForType)
+				.filter(i -> applicationContext instanceof ConfigurableApplicationContext)
+				.filter(n -> ((ConfigurableApplicationContext) applicationContext).getBeanFactory().getBeanDefinition(n).isPrimary())
+				.collect(Collectors.toList());
+
+			Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length
+					+ " beans for type " + interfaceName + ", but none marked as primary");
+			Assert.isTrue(primaryBeanNames.size() == 1, () -> "Found " + primaryBeanNames.size()
+					+ " beans for type " + interfaceName + " marked as primary");
+			beanName = primaryBeanNames.get(0);
+		} else {
+			beanName = beanNamesForType[0];
+		}
+
+		lazyTargetSource.setTargetBeanName(beanName);
 		lazyTargetSource.setBeanFactory(applicationContext);
 		ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
 		proxyFactory = objectPostProcessor.postProcess(proxyFactory);

+ 24 - 0
config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java

@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Primary;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 import org.springframework.security.access.annotation.Secured;
@@ -506,4 +507,27 @@ public class AuthenticationConfigurationTests {
 		@Autowired
 		Service service;
 	}
+
+	@Test
+	public void getAuthenticationManagerBeanWhenMultipleDefinedAndOnePrimaryThenNoException() throws Exception {
+		this.spring.register(MultipleAuthenticationManagerBeanConfig.class).autowire();
+		this.spring.getContext().getBeanFactory().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
+	}
+
+	@Configuration
+	@Import(AuthenticationConfiguration.class)
+	static class MultipleAuthenticationManagerBeanConfig {
+
+		@Bean
+		@Primary
+		public AuthenticationManager manager1() {
+			return mock(AuthenticationManager.class);
+		}
+
+		@Bean
+		public AuthenticationManager manager2() {
+			return mock(AuthenticationManager.class);
+		}
+
+	}
 }