@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     }

第47-50 行可以看出来,如果没有指定包,会调用 org.springframework.util.ClassUtils#getPackageName(java.lang.String) 获取类的包作为扫描路径。

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 获取。

补充: 对于类型不同,名称相同的处理,会发生覆盖。

 

补充:spring  org.springframework.context.annotation.Configuration#proxyBeanMethods 的作用

 proxyBeanMethods: 是@Configuration注解的一个属性,它用于控制@Bean方法的代理行为。从Spring 5开始,默认值为true。该属性接受一个布尔值,设置为true表示启用代理模式,设置为false表示禁用代理模式。

代理模式(Proxy Mode):

当proxyBeanMethods属性设置为true时,Spring会对@Configuration类进行CGLIB代理。CGLIB是一个强大的第三方库,用于在运行时生成Java类的子类。

对@Configuration类进行代理后,调用@Bean方法时,Spring会检查是否已经存在该Bean,如果存在,则直接返回已存在的Bean,否则调用方法创建新的Bean并缓存起来。
这样做的好处是,当多个@Bean方法之间存在相互调用时,可以保证对相同Bean的调用不会重复执行,提高了应用程序的性能。

禁用代理模式:

当proxyBeanMethods属性设置为false时,禁用了CGLIB代理。
在禁用代理模式下,Spring容器每次调用@Bean方法时都会执行一次方法体,不会缓存Bean对象。
这样做的好处是,每次调用@Bean方法都会重新创建一个新的Bean对象,适用于那些需要每次返回新实例的场景。

如何选择代理模式:
选择是否启用代理模式取决于应用程序的需求。
如果@Configuration类中的@Bean方法之间没有相互调用,并且Bean的创建不涉及复杂的逻辑,可以考虑启用代理模式,以提高性能。
如果@Bean方法之间有相互调用,或者Bean的创建逻辑比较复杂,为了保证每次调用都返回新的实例,可以禁用代理模式。

  简单理解:

// 为false CustomClassTest 创建2个; 为true CustomClassTest 创建1个而且创建调用链包含cglib 相关调用, 会缓存对象. 其实满足spring 单例的规则,所有的都走生命周期
@Configuration(proxyBeanMethods = false)
public class CustomClassTestConfiguration {

    @Bean
    public CustomClassTest customClassTest() {
        return new CustomClassTest();
    }

    @Bean
    public CustomClassTest2 customClassTest2() {
        return new CustomClassTest2(customClassTest());
    }
}

 

posted @ 2021-03-15 20:32  QiaoZhi  阅读(1881)  评论(0编辑  收藏  举报