diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java index 62c6e2b10d6..f2122b2f789 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-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. @@ -248,8 +248,10 @@ public interface ListableBeanFactory extends BeanFactory { *

Note that this method considers objects created by FactoryBeans, which means * that FactoryBeans will get initialized in order to determine their object type. * @param annotationType the type of annotation to look for + * (at class, interface or factory method level of the specified bean) * @return the names of all matching beans * @since 4.0 + * @see #findAnnotationOnBean */ String[] getBeanNamesForAnnotation(Class annotationType); @@ -259,22 +261,27 @@ public interface ListableBeanFactory extends BeanFactory { *

Note that this method considers objects created by FactoryBeans, which means * that FactoryBeans will get initialized in order to determine their object type. * @param annotationType the type of annotation to look for + * (at class, interface or factory method level of the specified bean) * @return a Map with the matching beans, containing the bean names as * keys and the corresponding bean instances as values * @throws BeansException if a bean could not be created * @since 3.0 + * @see #findAnnotationOnBean */ Map getBeansWithAnnotation(Class annotationType) throws BeansException; /** - * Find an {@link Annotation} of {@code annotationType} on the specified - * bean, traversing its interfaces and super classes if no annotation can be - * found on the given class itself. + * Find an {@link Annotation} of {@code annotationType} on the specified bean, + * traversing its interfaces and super classes if no annotation can be found on + * the given class itself, as well as checking the bean's factory method (if any). * @param beanName the name of the bean to look for annotations on - * @param annotationType the annotation class to look for + * @param annotationType the type of annotation to look for + * (at class, interface or factory method level of the specified bean) * @return the annotation of the given type if found, or {@code null} otherwise * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @since 3.0 + * @see #getBeanNamesForAnnotation + * @see #getBeansWithAnnotation */ @Nullable A findAnnotationOnBean(String beanName, Class annotationType) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index e916ab7121e..09a8c31c445 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -678,23 +678,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto Class beanType = getType(beanName); if (beanType != null) { - MergedAnnotation annotation = MergedAnnotations.from(beanType, - SearchStrategy.EXHAUSTIVE).get(annotationType); + MergedAnnotation annotation = + MergedAnnotations.from(beanType, SearchStrategy.EXHAUSTIVE).get(annotationType); if (annotation.isPresent()) { return annotation; } } if (containsBeanDefinition(beanName)) { - BeanDefinition bd = getMergedBeanDefinition(beanName); - if (bd instanceof AbstractBeanDefinition) { - AbstractBeanDefinition abd = (AbstractBeanDefinition) bd; - if (abd.hasBeanClass()) { - Class beanClass = abd.getBeanClass(); - if (beanClass != beanType) { - return MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE).get(annotationType); + RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); + if (bd.hasBeanClass()) { + Class beanClass = bd.getBeanClass(); + if (beanClass != beanType) { + MergedAnnotation annotation = + MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE).get(annotationType); + if (annotation.isPresent()) { + return annotation; } } } + Method factoryMethod = bd.getResolvedFactoryMethod(); + if (factoryMethod != null) { + MergedAnnotation annotation = + MergedAnnotations.from(factoryMethod, SearchStrategy.EXHAUSTIVE).get(annotationType); + if (annotation.isPresent()) { + return annotation; + } + } } return MergedAnnotation.missing(); } @@ -1988,10 +1997,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override @Nullable public Object getOrderSource(Object obj) { - RootBeanDefinition beanDefinition = getRootBeanDefinition(this.instancesToBeanNames.get(obj)); - if (beanDefinition == null) { + String beanName = this.instancesToBeanNames.get(obj); + if (beanName == null || !containsBeanDefinition(beanName)) { return null; } + RootBeanDefinition beanDefinition = getMergedLocalBeanDefinition(beanName); List sources = new ArrayList<>(2); Method factoryMethod = beanDefinition.getResolvedFactoryMethod(); if (factoryMethod != null) { @@ -2003,17 +2013,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } return sources.toArray(); } - - @Nullable - private RootBeanDefinition getRootBeanDefinition(@Nullable String beanName) { - if (beanName != null && containsBeanDefinition(beanName)) { - BeanDefinition bd = getMergedBeanDefinition(beanName); - if (bd instanceof RootBeanDefinition) { - return (RootBeanDefinition) bd; - } - } - return null; - } } } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java index a067a4e83c5..bc7b2eff912 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-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. @@ -129,6 +129,16 @@ public class BeanMethodQualificationTests { assertThat(pojo.testBean.getName(), equalTo("interesting")); } + @Test + public void testBeanNamesForAnnotation() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(StandardConfig.class); + assertArrayEquals(new String[] {"beanMethodQualificationTests.StandardConfig"}, + ctx.getBeanNamesForAnnotation(Configuration.class)); + assertArrayEquals(new String[] {}, ctx.getBeanNamesForAnnotation(Scope.class)); + assertArrayEquals(new String[] {"testBean1"}, ctx.getBeanNamesForAnnotation(Lazy.class)); + assertArrayEquals(new String[] {"testBean2"}, ctx.getBeanNamesForAnnotation(Boring.class)); + } + @Configuration static class StandardConfig {