@Configuration 注入對象的過程以及創建過程


  寫在前面,@Configuration注解創建對象可以使用靜態方法,也可以使用實例方法。  如果使用靜態方法,獲取對象getBean()的時候不會創建@Configuration 配置類本身,如果是實例方法,獲取bean需要先創建配置類自己,然后反射創建獲取的bean。

1. 測試

1. 類信息

UserDao:

package cn.qz.user;

import org.springframework.stereotype.Component;

@Component
public class UserDao {

    public UserDao() {
        System.out.println("UserDao created ====== ");
    }

}

UserService: 采用Configuration類注入

package cn.qz.user;

import org.springframework.beans.factory.annotation.Autowired;

public class UserService {

    // 構造
    public UserService() {
        System.out.println("=============UserService=====");
    }

    @Autowired
    public void setUserDao(UserDao userDao) {
        System.out.println("cn.qz.user.UserService.setUserDao====userDao");
    }

}

UserService2: 采用Configuration類靜態方法注入

package cn.qz.user;

public class UserService2 {

    public UserService2 () {
        System.out.println("UserService2========");
    }
}

BeanConfiguration: 配置類:

package cn.qz.user;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfiguration {

    public BeanConfiguration() {
        System.out.println("BeanConfiguration created====");
    }

    @Bean
    public static UserService2 userService2() {
        return new UserService2();
    }

    @Bean
    public UserService userService() {
        return new UserService();
    }
}

2. 測試信息:

(1) 測試一

package cn.qz;

import cn.qz.user.UserService2;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
//@Import({ImpConfiguration.class})
//@EnableAspectJAutoProxy
public class App implements InitializingBean, ApplicationContextAware {

    public App() {
        System.out.println("App created ======");
    }

    public static void main(String[] args) {
        //在指定目錄下生成動態代理類,我們可以反編譯看一下里面到底是一些什么東西
//        System.setProperty("cglib.debugLocation", "F:/proxy");
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
        applicationContext.close();
    }

    private ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cn.qz.App.afterPropertiesSet    afterPropertiesSet");
        applicationContext.getBean(UserService2.class);
    }

    @Override
    public void setApplicationContext(ApplicationContext ac) throws BeansException {
        this.applicationContext = ac;
    }
}

結果:

App created ======
cn.qz.App.afterPropertiesSet    afterPropertiesSet
UserService2========
BeanConfiguration created====
UserDao created ====== 
=============UserService=====
cn.qz.user.UserService.setUserDao====userDao

(2) 測試二:

package cn.qz;

import cn.qz.user.UserService1;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
//@Import({ImpConfiguration.class})
//@EnableAspectJAutoProxy
public class App implements InitializingBean, ApplicationContextAware {

    public App() {
        System.out.println("App created ======");
    }

    public static void main(String[] args) {
        //在指定目錄下生成動態代理類,我們可以反編譯看一下里面到底是一些什么東西
//        System.setProperty("cglib.debugLocation", "F:/proxy");
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
        applicationContext.close();
    }

    private ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cn.qz.App.afterPropertiesSet    afterPropertiesSet");
        applicationContext.getBean(UserService.class);
    }

    @Override
    public void setApplicationContext(ApplicationContext ac) throws BeansException {
        this.applicationContext = ac;
    }
}

結果:

App created ======
cn.qz.App.afterPropertiesSet    afterPropertiesSet
BeanConfiguration created====
=============UserService=====
UserDao created ====== 
cn.qz.user.UserService.setUserDao====userDao
UserService2========

  可以看出,在上面過程中,在InitializingBean#afterPropertiesSet 獲取容器中@Configuration 注入的對象,如果是靜態注入的不會創建配置類;如果是實例對象會創建配置類自身。 這個也很好理解,如果是實例方法必須有實例才可以反射調用方法。

2. @Configuration以及內部@Bean 注入過程

  回顧之前的:

1. org.springframework.context.support.AbstractApplicationContext#refresh 標志着IoC過程的開始

2.  方法內部調用org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors 調用BeanFactory的后處理器, 是在注入之后,實例化之前調用,因此可以用於動態的注入BeanDefinition信息。

3.  接下來調用到org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

4.  方法調用到org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

5.  繼續調用到org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions    核心邏輯就是在這里(這里的解析是個遞歸的過程: 先用parser解析出所有的Configuration類,然后用reader 來loadBeanDefinitions )

  1     public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  2         List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  3         String[] candidateNames = registry.getBeanDefinitionNames();
  4 
  5         for (String beanName : candidateNames) {
  6             BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  7             if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
  8                     ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
  9                 if (logger.isDebugEnabled()) {
 10                     logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
 11                 }
 12             }
 13             else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
 14                 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
 15             }
 16         }
 17 
 18         // Return immediately if no @Configuration classes were found
 19         if (configCandidates.isEmpty()) {
 20             return;
 21         }
 22 
 23         // Sort by previously determined @Order value, if applicable
 24         configCandidates.sort((bd1, bd2) -> {
 25             int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
 26             int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
 27             return Integer.compare(i1, i2);
 28         });
 29 
 30         // Detect any custom bean name generation strategy supplied through the enclosing application context
 31         SingletonBeanRegistry sbr = null;
 32         if (registry instanceof SingletonBeanRegistry) {
 33             sbr = (SingletonBeanRegistry) registry;
 34             if (!this.localBeanNameGeneratorSet) {
 35                 BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
 36                 if (generator != null) {
 37                     this.componentScanBeanNameGenerator = generator;
 38                     this.importBeanNameGenerator = generator;
 39                 }
 40             }
 41         }
 42 
 43         if (this.environment == null) {
 44             this.environment = new StandardEnvironment();
 45         }
 46 
 47         // Parse each @Configuration class
 48         ConfigurationClassParser parser = new ConfigurationClassParser(
 49                 this.metadataReaderFactory, this.problemReporter, this.environment,
 50                 this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 51 
 52         Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 53         Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 54         do {
 55             parser.parse(candidates);
 56             parser.validate();
 57 
 58             Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 59             configClasses.removeAll(alreadyParsed);
 60 
 61             // Read the model and create bean definitions based on its content
 62             if (this.reader == null) {
 63                 this.reader = new ConfigurationClassBeanDefinitionReader(
 64                         registry, this.sourceExtractor, this.resourceLoader, this.environment,
 65                         this.importBeanNameGenerator, parser.getImportRegistry());
 66             }
 67             this.reader.loadBeanDefinitions(configClasses);
 68             alreadyParsed.addAll(configClasses);
 69 
 70             candidates.clear();
 71             if (registry.getBeanDefinitionCount() > candidateNames.length) {
 72                 String[] newCandidateNames = registry.getBeanDefinitionNames();
 73                 Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
 74                 Set<String> alreadyParsedClasses = new HashSet<>();
 75                 for (ConfigurationClass configurationClass : alreadyParsed) {
 76                     alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
 77                 }
 78                 for (String candidateName : newCandidateNames) {
 79                     if (!oldCandidateNames.contains(candidateName)) {
 80                         BeanDefinition bd = registry.getBeanDefinition(candidateName);
 81                         if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
 82                                 !alreadyParsedClasses.contains(bd.getBeanClassName())) {
 83                             candidates.add(new BeanDefinitionHolder(bd, candidateName));
 84                         }
 85                     }
 86                 }
 87                 candidateNames = newCandidateNames;
 88             }
 89         }
 90         while (!candidates.isEmpty());
 91 
 92         // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
 93         if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
 94             sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
 95         }
 96 
 97         if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
 98             // Clear cache in externally provided MetadataReaderFactory; this is a no-op
 99             // for a shared cache since it'll be cleared by the ApplicationContext.
100             ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
101         }
102     }

(1) 上面代碼代碼第3行拿到的配置類信息如下:

(2) 接下來5-16 行循環判斷是配置類的BeanDefinitionHolder

(3) 19行判斷如果沒有配置類就返回

(4) 接下來第55行 使用創建的parser 開始解析配置類, 解析出Set<ConfigurationClass> 並存入parser 的屬性中,其解析過程如下:

1》 調用到方法:org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass

 1     protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
 2         if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
 3             return;
 4         }
 5 
 6         ConfigurationClass existingClass = this.configurationClasses.get(configClass);
 7         if (existingClass != null) {
 8             if (configClass.isImported()) {
 9                 if (existingClass.isImported()) {
10                     existingClass.mergeImportedBy(configClass);
11                 }
12                 // Otherwise ignore new imported config class; existing non-imported class overrides it.
13                 return;
14             }
15             else {
16                 // Explicit bean definition found, probably replacing an import.
17                 // Let's remove the old one and go with the new one.
18                 this.configurationClasses.remove(configClass);
19                 this.knownSuperclasses.values().removeIf(configClass::equals);
20             }
21         }
22 
23         // Recursively process the configuration class and its superclass hierarchy.
24         SourceClass sourceClass = asSourceClass(configClass);
25         do {
26             sourceClass = doProcessConfigurationClass(configClass, sourceClass);
27         }
28         while (sourceClass != null);
29 
30         this.configurationClasses.put(configClass, configClass);
31     }

  可以看到第26 行遞歸的解析Configuration 類; 第30 行存入自身的緩存map

2》 上面第26行調用 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass如下:

 1     @Nullable
 2     protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
 3             throws IOException {
 4 
 5         if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
 6             // Recursively process any member (nested) classes first
 7             processMemberClasses(configClass, sourceClass);
 8         }
 9 
10         // Process any @PropertySource annotations
11         for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
12                 sourceClass.getMetadata(), PropertySources.class,
13                 org.springframework.context.annotation.PropertySource.class)) {
14             if (this.environment instanceof ConfigurableEnvironment) {
15                 processPropertySource(propertySource);
16             }
17             else {
18                 logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
19                         "]. Reason: Environment must implement ConfigurableEnvironment");
20             }
21         }
22 
23         // Process any @ComponentScan annotations
24         Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
25                 sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
26         if (!componentScans.isEmpty() &&
27                 !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
28             for (AnnotationAttributes componentScan : componentScans) {
29                 // The config class is annotated with @ComponentScan -> perform the scan immediately
30                 Set<BeanDefinitionHolder> scannedBeanDefinitions =
31                         this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
32                 // Check the set of scanned definitions for any further config classes and parse recursively if needed
33                 for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
34                     BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
35                     if (bdCand == null) {
36                         bdCand = holder.getBeanDefinition();
37                     }
38                     if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
39                         parse(bdCand.getBeanClassName(), holder.getBeanName());
40                     }
41                 }
42             }
43         }
44 
45         // Process any @Import annotations
46         processImports(configClass, sourceClass, getImports(sourceClass), true);
47 
48         // Process any @ImportResource annotations
49         AnnotationAttributes importResource =
50                 AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
51         if (importResource != null) {
52             String[] resources = importResource.getStringArray("locations");
53             Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
54             for (String resource : resources) {
55                 String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
56                 configClass.addImportedResource(resolvedResource, readerClass);
57             }
58         }
59 
60         // Process individual @Bean methods
61         Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
62         for (MethodMetadata methodMetadata : beanMethods) {
63             configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
64         }
65 
66         // Process default methods on interfaces
67         processInterfaces(configClass, sourceClass);
68 
69         // Process superclass, if any
70         if (sourceClass.getMetadata().hasSuperClass()) {
71             String superclass = sourceClass.getMetadata().getSuperClassName();
72             if (superclass != null && !superclass.startsWith("java") &&
73                     !this.knownSuperclasses.containsKey(superclass)) {
74                 this.knownSuperclasses.put(superclass, configClass);
75                 // Superclass found, return its annotation metadata and recurse
76                 return sourceClass.getSuperClass();
77             }
78         }
79 
80         // No superclass -> processing is complete
81         return null;
82     }

2.1》第31行掃描到的兩個BeanDefinitionHolder如下:(這里根據App的ComponentScan指定的包掃描)

org.springframework.context.annotation.ComponentScanAnnotationParser#parse 方法如下:

 1     public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
 2         ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
 3                 componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
 4 
 5         Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
 6         boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
 7         scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
 8                 BeanUtils.instantiateClass(generatorClass));
 9 
10         ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
11         if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
12             scanner.setScopedProxyMode(scopedProxyMode);
13         }
14         else {
15             Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
16             scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
17         }
18 
19         scanner.setResourcePattern(componentScan.getString("resourcePattern"));
20 
21         for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
22             for (TypeFilter typeFilter : typeFiltersFor(filter)) {
23                 scanner.addIncludeFilter(typeFilter);
24             }
25         }
26         for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
27             for (TypeFilter typeFilter : typeFiltersFor(filter)) {
28                 scanner.addExcludeFilter(typeFilter);
29             }
30         }
31 
32         boolean lazyInit = componentScan.getBoolean("lazyInit");
33         if (lazyInit) {
34             scanner.getBeanDefinitionDefaults().setLazyInit(true);
35         }
36 
37         Set<String> basePackages = new LinkedHashSet<>();
38         String[] basePackagesArray = componentScan.getStringArray("basePackages");
39         for (String pkg : basePackagesArray) {
40             String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
41                     ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
42             Collections.addAll(basePackages, tokenized);
43         }
44         for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
45             basePackages.add(ClassUtils.getPackageName(clazz));
46         }
47         if (basePackages.isEmpty()) {
48             basePackages.add(ClassUtils.getPackageName(declaringClass));
49         }
50 
51         scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
52             @Override
53             protected boolean matchClassName(String className) {
54                 return declaringClass.equals(className);
55             }
56         });
57         return scanner.doScan(StringUtils.toStringArray(basePackages));
58     }

57 行調用掃描方法:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

 1     protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
 2         Assert.notEmpty(basePackages, "At least one base package must be specified");
 3         Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
 4         for (String basePackage : basePackages) {
 5             Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
 6             for (BeanDefinition candidate : candidates) {
 7                 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
 8                 candidate.setScope(scopeMetadata.getScopeName());
 9                 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
10                 if (candidate instanceof AbstractBeanDefinition) {
11                     postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
12                 }
13                 if (candidate instanceof AnnotatedBeanDefinition) {
14                     AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
15                 }
16                 if (checkCandidate(beanName, candidate)) {
17                     BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
18                     definitionHolder =
19                             AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
20                     beanDefinitions.add(definitionHolder);
21                     registerBeanDefinition(definitionHolder, this.registry);
22                 }
23             }
24         }
25         return beanDefinitions;
26     }

11行和14行是設置了一些默認定制BeanDefinition應有的屬性。16 行會檢查beanDefinition 是否已經注冊到BeanFactory, 如果沒注冊進去,在21 行注冊進去。( 也就是將掃描到的Configuration以及其他組件注冊進去作為配置類)

2.2》第39行繼續調用parse 進行遞歸解析。會遞歸調用到org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass 方法。 先解析beanConfiguration,然后進行第二次循環解析userDao(可以看到會將userDao也作為配置類進行解析)。

2.3》第61行會解析配置類里面的@Bean 注解聲明的bean,如下:org.springframework.context.annotation.ConfigurationClassParser#retrieveBeanMethodMetadata

    /**
     * Retrieve the metadata for all <code>@Bean</code> methods.
     */
    private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
        AnnotationMetadata original = sourceClass.getMetadata();
        Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
        if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
            // Try reading the class file via ASM for deterministic declaration order...
            // Unfortunately, the JVM's standard reflection returns methods in arbitrary
            // order, even between different runs of the same application on the same JVM.
            try {
                AnnotationMetadata asm =
                        this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
                Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
                if (asmMethods.size() >= beanMethods.size()) {
                    Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
                    for (MethodMetadata asmMethod : asmMethods) {
                        for (MethodMetadata beanMethod : beanMethods) {
                            if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                                selectedMethods.add(beanMethod);
                                break;
                            }
                        }
                    }
                    if (selectedMethods.size() == beanMethods.size()) {
                        // All reflection-detected methods found in ASM method set -> proceed
                        beanMethods = selectedMethods;
                    }
                }
            }
            catch (IOException ex) {
                logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
                // No worries, let's continue with the reflection metadata we started with...
            }
        }
        return beanMethods;
    }

2.4》doProcessConfigurationClass第63 行會創建一個BeanMethod 對象存入config中。

 

最終返回去的configClasses如下:

 

 (5) 然后processConfigBeanDefinitions代碼塊67 行調用this.reader.loadBeanDefinitions 加載beanDefinition信息,org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 如下:

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }

然后調用到:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

 1     private void loadBeanDefinitionsForConfigurationClass(
 2             ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
 3 
 4         if (trackedConditionEvaluator.shouldSkip(configClass)) {
 5             String beanName = configClass.getBeanName();
 6             if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
 7                 this.registry.removeBeanDefinition(beanName);
 8             }
 9             this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
10             return;
11         }
12 
13         if (configClass.isImported()) {
14             registerBeanDefinitionForImportedConfigurationClass(configClass);
15         }
16         for (BeanMethod beanMethod : configClass.getBeanMethods()) {
17             loadBeanDefinitionsForBeanMethod(beanMethod);
18         }
19 
20         loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
21         loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
22     }

第17 行是加載上一步parser 解析出的@Bean 注解聲明的對象,org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod如下:

  1     private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
  2         ConfigurationClass configClass = beanMethod.getConfigurationClass();
  3         MethodMetadata metadata = beanMethod.getMetadata();
  4         String methodName = metadata.getMethodName();
  5 
  6         // Do we need to mark the bean as skipped by its condition?
  7         if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
  8             configClass.skippedBeanMethods.add(methodName);
  9             return;
 10         }
 11         if (configClass.skippedBeanMethods.contains(methodName)) {
 12             return;
 13         }
 14 
 15         AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
 16         Assert.state(bean != null, "No @Bean annotation attributes");
 17 
 18         // Consider name and any aliases
 19         List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
 20         String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
 21 
 22         // Register aliases even when overridden
 23         for (String alias : names) {
 24             this.registry.registerAlias(beanName, alias);
 25         }
 26 
 27         // Has this effectively been overridden before (e.g. via XML)?
 28         if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
 29             if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
 30                 throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
 31                         beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
 32                         "' clashes with bean name for containing configuration class; please make those names unique!");
 33             }
 34             return;
 35         }
 36 
 37         ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
 38         beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
 39 
 40         if (metadata.isStatic()) {
 41             // static @Bean method
 42             beanDef.setBeanClassName(configClass.getMetadata().getClassName());
 43             beanDef.setFactoryMethodName(methodName);
 44         }
 45         else {
 46             // instance @Bean method
 47             beanDef.setFactoryBeanName(configClass.getBeanName());
 48             beanDef.setUniqueFactoryMethodName(methodName);
 49         }
 50         beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
 51         beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
 52                 SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
 53 
 54         AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
 55 
 56         Autowire autowire = bean.getEnum("autowire");
 57         if (autowire.isAutowire()) {
 58             beanDef.setAutowireMode(autowire.value());
 59         }
 60 
 61         boolean autowireCandidate = bean.getBoolean("autowireCandidate");
 62         if (!autowireCandidate) {
 63             beanDef.setAutowireCandidate(false);
 64         }
 65 
 66         String initMethodName = bean.getString("initMethod");
 67         if (StringUtils.hasText(initMethodName)) {
 68             beanDef.setInitMethodName(initMethodName);
 69         }
 70 
 71         String destroyMethodName = bean.getString("destroyMethod");
 72         beanDef.setDestroyMethodName(destroyMethodName);
 73 
 74         // Consider scoping
 75         ScopedProxyMode proxyMode = ScopedProxyMode.NO;
 76         AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
 77         if (attributes != null) {
 78             beanDef.setScope(attributes.getString("value"));
 79             proxyMode = attributes.getEnum("proxyMode");
 80             if (proxyMode == ScopedProxyMode.DEFAULT) {
 81                 proxyMode = ScopedProxyMode.NO;
 82             }
 83         }
 84 
 85         // Replace the original bean definition with the target one, if necessary
 86         BeanDefinition beanDefToRegister = beanDef;
 87         if (proxyMode != ScopedProxyMode.NO) {
 88             BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
 89                     new BeanDefinitionHolder(beanDef, beanName), this.registry,
 90                     proxyMode == ScopedProxyMode.TARGET_CLASS);
 91             beanDefToRegister = new ConfigurationClassBeanDefinition(
 92                     (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
 93         }
 94 
 95         if (logger.isTraceEnabled()) {
 96             logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
 97                     configClass.getMetadata().getClassName(), beanName));
 98         }
 99         this.registry.registerBeanDefinition(beanName, beanDefToRegister);
100     }

  第37 行創建了一個ConfigurationClassBeanDefinition;接下來判斷@Bean 聲明的方法是否是靜態方法啊,如果是靜態方法設置beanDef.className 屬性和;如果是實例方法,設置beanDef.factoryBeanName 屬性。 兩者都會設置factoryMethodName 屬性,也就是創建對象的方法名稱。第99 行注冊到BeanFactory。(這里可以看到方法名是默認作為beanName注冊到IoC容器中)

3. 創建對象過程

  在之前了解到org.springframework.context.support.AbstractApplicationContext#refresh 方法標記着IoC的開始:

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

  org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization這里會開始准備單例對象。經過一系列操作會到達getBean方法,就從這個方法開始研究。

    這個方法經過一系列的操作和判斷之后會到達org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance 方法:

 1     protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
 2         Class<?> beanClass = resolveBeanClass(mbd, beanName);
 3 
 4         if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
 5             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 6                     "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
 7         }
 8 
 9         Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
10         if (instanceSupplier != null) {
11             return obtainFromSupplier(instanceSupplier, beanName);
12         }
13 
14         if (mbd.getFactoryMethodName() != null) {
15             return instantiateUsingFactoryMethod(beanName, mbd, args);
16         }
17 
18         // Shortcut when re-creating the same bean...
19         boolean resolved = false;
20         boolean autowireNecessary = false;
21         if (args == null) {
22             synchronized (mbd.constructorArgumentLock) {
23                 if (mbd.resolvedConstructorOrFactoryMethod != null) {
24                     resolved = true;
25                     autowireNecessary = mbd.constructorArgumentsResolved;
26                 }
27             }
28         }
29         if (resolved) {
30             if (autowireNecessary) {
31                 return autowireConstructor(beanName, mbd, null, null);
32             }
33             else {
34                 return instantiateBean(beanName, mbd);
35             }
36         }
37 
38         // Candidate constructors for autowiring?
39         Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
40         if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
41                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
42             return autowireConstructor(beanName, mbd, ctors, args);
43         }
44 
45         // Preferred constructors for default construction?
46         ctors = mbd.getPreferredConstructors();
47         if (ctors != null) {
48             return autowireConstructor(beanName, mbd, ctors, null);
49         }
50 
51         // No special handling: simply use no-arg constructor.
52         return instantiateBean(beanName, mbd);
53     }

  在上面注冊過程中了解到,如果是@Configuration 生成的對象,其BeanDefinition類型是ConfigurationClassBeanDefinition;並且其factoryMethodName 是@Bean 聲明的方法; 如果是靜態方法beanClass 為@Configuration 所在的配置類,如果是實例方法beanName是@Configuration 配置類在容器中的beanName。比如上面BeanConfiguration兩個方法對應的BeanDefinition的區別:

(1)userService 對應的:

 (2) userService2 對應的

 

最后會調用到方法org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod:

  1     public BeanWrapper instantiateUsingFactoryMethod(
  2             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
  3 
  4         BeanWrapperImpl bw = new BeanWrapperImpl();
  5         this.beanFactory.initBeanWrapper(bw);
  6 
  7         Object factoryBean;
  8         Class<?> factoryClass;
  9         boolean isStatic;
 10 
 11         String factoryBeanName = mbd.getFactoryBeanName();
 12         if (factoryBeanName != null) {
 13             if (factoryBeanName.equals(beanName)) {
 14                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
 15                         "factory-bean reference points back to the same bean definition");
 16             }
 17             factoryBean = this.beanFactory.getBean(factoryBeanName);
 18             if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
 19                 throw new ImplicitlyAppearedSingletonException();
 20             }
 21             factoryClass = factoryBean.getClass();
 22             isStatic = false;
 23         }
 24         else {
 25             // It's a static factory method on the bean class.
 26             if (!mbd.hasBeanClass()) {
 27                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
 28                         "bean definition declares neither a bean class nor a factory-bean reference");
 29             }
 30             factoryBean = null;
 31             factoryClass = mbd.getBeanClass();
 32             isStatic = true;
 33         }
 34 
 35         Method factoryMethodToUse = null;
 36         ArgumentsHolder argsHolderToUse = null;
 37         Object[] argsToUse = null;
 38 
 39         if (explicitArgs != null) {
 40             argsToUse = explicitArgs;
 41         }
 42         else {
 43             Object[] argsToResolve = null;
 44             synchronized (mbd.constructorArgumentLock) {
 45                 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
 46                 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
 47                     // Found a cached factory method...
 48                     argsToUse = mbd.resolvedConstructorArguments;
 49                     if (argsToUse == null) {
 50                         argsToResolve = mbd.preparedConstructorArguments;
 51                     }
 52                 }
 53             }
 54             if (argsToResolve != null) {
 55                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
 56             }
 57         }
 58 
 59         if (factoryMethodToUse == null || argsToUse == null) {
 60             // Need to determine the factory method...
 61             // Try all methods with this name to see if they match the given arguments.
 62             factoryClass = ClassUtils.getUserClass(factoryClass);
 63 
 64             Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
 65             List<Method> candidateList = new ArrayList<>();
 66             for (Method candidate : rawCandidates) {
 67                 if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
 68                     candidateList.add(candidate);
 69                 }
 70             }
 71 
 72             if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
 73                 Method uniqueCandidate = candidateList.get(0);
 74                 if (uniqueCandidate.getParameterCount() == 0) {
 75                     mbd.factoryMethodToIntrospect = uniqueCandidate;
 76                     synchronized (mbd.constructorArgumentLock) {
 77                         mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
 78                         mbd.constructorArgumentsResolved = true;
 79                         mbd.resolvedConstructorArguments = EMPTY_ARGS;
 80                     }
 81                     bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
 82                     return bw;
 83                 }
 84             }
 85 
 86             Method[] candidates = candidateList.toArray(new Method[0]);
 87             AutowireUtils.sortFactoryMethods(candidates);
 88 
 89             ConstructorArgumentValues resolvedValues = null;
 90             boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
 91             int minTypeDiffWeight = Integer.MAX_VALUE;
 92             Set<Method> ambiguousFactoryMethods = null;
 93 
 94             int minNrOfArgs;
 95             if (explicitArgs != null) {
 96                 minNrOfArgs = explicitArgs.length;
 97             }
 98             else {
 99                 // We don't have arguments passed in programmatically, so we need to resolve the
100                 // arguments specified in the constructor arguments held in the bean definition.
101                 if (mbd.hasConstructorArgumentValues()) {
102                     ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
103                     resolvedValues = new ConstructorArgumentValues();
104                     minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
105                 }
106                 else {
107                     minNrOfArgs = 0;
108                 }
109             }
110 
111             LinkedList<UnsatisfiedDependencyException> causes = null;
112 
113             for (Method candidate : candidates) {
114                 Class<?>[] paramTypes = candidate.getParameterTypes();
115 
116                 if (paramTypes.length >= minNrOfArgs) {
117                     ArgumentsHolder argsHolder;
118 
119                     if (explicitArgs != null) {
120                         // Explicit arguments given -> arguments length must match exactly.
121                         if (paramTypes.length != explicitArgs.length) {
122                             continue;
123                         }
124                         argsHolder = new ArgumentsHolder(explicitArgs);
125                     }
126                     else {
127                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
128                         try {
129                             String[] paramNames = null;
130                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
131                             if (pnd != null) {
132                                 paramNames = pnd.getParameterNames(candidate);
133                             }
134                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
135                                     paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
136                         }
137                         catch (UnsatisfiedDependencyException ex) {
138                             if (logger.isTraceEnabled()) {
139                                 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
140                             }
141                             // Swallow and try next overloaded factory method.
142                             if (causes == null) {
143                                 causes = new LinkedList<>();
144                             }
145                             causes.add(ex);
146                             continue;
147                         }
148                     }
149 
150                     int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
151                             argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
152                     // Choose this factory method if it represents the closest match.
153                     if (typeDiffWeight < minTypeDiffWeight) {
154                         factoryMethodToUse = candidate;
155                         argsHolderToUse = argsHolder;
156                         argsToUse = argsHolder.arguments;
157                         minTypeDiffWeight = typeDiffWeight;
158                         ambiguousFactoryMethods = null;
159                     }
160                     // Find out about ambiguity: In case of the same type difference weight
161                     // for methods with the same number of parameters, collect such candidates
162                     // and eventually raise an ambiguity exception.
163                     // However, only perform that check in non-lenient constructor resolution mode,
164                     // and explicitly ignore overridden methods (with the same parameter signature).
165                     else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
166                             !mbd.isLenientConstructorResolution() &&
167                             paramTypes.length == factoryMethodToUse.getParameterCount() &&
168                             !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
169                         if (ambiguousFactoryMethods == null) {
170                             ambiguousFactoryMethods = new LinkedHashSet<>();
171                             ambiguousFactoryMethods.add(factoryMethodToUse);
172                         }
173                         ambiguousFactoryMethods.add(candidate);
174                     }
175                 }
176             }
177 
178             if (factoryMethodToUse == null) {
179                 if (causes != null) {
180                     UnsatisfiedDependencyException ex = causes.removeLast();
181                     for (Exception cause : causes) {
182                         this.beanFactory.onSuppressedException(cause);
183                     }
184                     throw ex;
185                 }
186                 List<String> argTypes = new ArrayList<>(minNrOfArgs);
187                 if (explicitArgs != null) {
188                     for (Object arg : explicitArgs) {
189                         argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
190                     }
191                 }
192                 else if (resolvedValues != null) {
193                     Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
194                     valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
195                     valueHolders.addAll(resolvedValues.getGenericArgumentValues());
196                     for (ValueHolder value : valueHolders) {
197                         String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
198                                 (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
199                         argTypes.add(argType);
200                     }
201                 }
202                 String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
203                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
204                         "No matching factory method found: " +
205                         (mbd.getFactoryBeanName() != null ?
206                             "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
207                         "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
208                         "Check that a method with the specified name " +
209                         (minNrOfArgs > 0 ? "and arguments " : "") +
210                         "exists and that it is " +
211                         (isStatic ? "static" : "non-static") + ".");
212             }
213             else if (void.class == factoryMethodToUse.getReturnType()) {
214                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
215                         "Invalid factory method '" + mbd.getFactoryMethodName() +
216                         "': needs to have a non-void return type!");
217             }
218             else if (ambiguousFactoryMethods != null) {
219                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
220                         "Ambiguous factory method matches found in bean '" + beanName + "' " +
221                         "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
222                         ambiguousFactoryMethods);
223             }
224 
225             if (explicitArgs == null && argsHolderToUse != null) {
226                 mbd.factoryMethodToIntrospect = factoryMethodToUse;
227                 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
228             }
229         }
230 
231         Assert.state(argsToUse != null, "Unresolved factory method arguments");
232         bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
233         return bw;
234     }

 

這里面第17 行會先調用factoryBeanName 對象,也就是configuration 類對象自身;然后下面反射開始創建對象。 

 

 

補充:經過上面查看,@Component 也會被作為配置類遞歸的掃描其注入的相關bean,測試如下:

1. 創建一個GroupService類

package cn.qz.user;

public class GroupService {

    public GroupService() {
        System.out.println("groupService construct +++");
    }
}

2. 修改UserDao,使用@Bean 注入對象

package cn.qz.user;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class UserDao {

    public UserDao() {
        System.out.println("UserDao created ====== ");
    }

    @Bean
    public GroupService groupService() {
        return new GroupService();
    }

}

結果:

App created ======
cn.qz.App.afterPropertiesSet    afterPropertiesSet
BeanConfiguration created====
=============UserService=====
UserDao created ====== 
cn.qz.user.UserService.setUserDao====userDao
UserService2========
groupService construct +++

補充: 對於相同類型不同名稱的bean的處理 

package cn.qz.user;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfiguration {

    public BeanConfiguration() {
        System.out.println("BeanConfiguration created====");
    }

//    @Bean("")
//    public static UserService2 userService2() {
//        return new UserService2();
//    }

    @Bean
    public UserService userService() {
        return new UserService();
    }

    @Bean
    public UserService userService2() {
        return new UserService();
    }
}

測試類:

package cn.qz;

import cn.qz.beandefinitionproperty.Bean1;
import cn.qz.beandefinitionproperty.TestBean;
import cn.qz.factorybean.TestFactoryBean;
import cn.qz.user.UserService;
import cn.qz.user.UserService2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import java.util.Arrays;

@ComponentScan
public class App {

    public App() {
        System.out.println("App created ======");
    }

    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));
        UserService testBean = applicationContext.getBean(UserService.class);
        System.out.println(testBean);

        applicationContext.close();
    }

}

結果:

[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, app, beanConfiguration, myLifecyle, userDao, userService, userService2, groupService]
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.qz.user.UserService' available: expected single matching bean but found 2: userService,userService2
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1169)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:419)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:348)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1124)
    at cn.qz.App.main(App.java:36)

> Task :mytest:App.main() FAILED

  可以看出來注冊了兩個Bean, 但是獲取的時候報錯,沒有獲取到唯一的bean, 可以根據name 獲取。

補充: 對於類型不同,名稱相同的處理,會發生覆蓋。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM