@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()); } }