解析父类
if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } }
解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析
对父类进行判别其是否需要处理:父类不是以 java 开头的、父类集合中未存在(防止重复处理)
满足以后返回到外层方法:doProcessConfigurationClass,do-while 循环
do { // 解析各种注解 sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); } while (sourceClass != null);
processConfigBeanDefinitions 后置结束工作
parser#validate
解析完的 Configuration 配置类进行校验
public void validate(ProblemReporter problemReporter) { // 获取 @Configuration 注解的属性值,除非配置类声明为 proxyBeanMethods=false 不适用 CGLIB 代理模式,否则的话不可能为 final 类 Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName()); if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) { // 如果配置类是final类型,则抛出异常 if (this.metadata.isFinal()) { problemReporter.error(new FinalConfigurationProblem()); } // 校验配置类中@Bean定义的方法 for (BeanMethod beanMethod : this.beanMethods) { beanMethod.validate(problemReporter); } } }
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
在此方法调用之前,注入的 BeanDefinition 都是 Configuration 配置类中定义的内部 bean,因为配置类依赖于这些内部的实例,所以后面这部分工作就是处理配置类 BD 加载工作.
// 获取所有的 bean,包括扫描的 bean 对象,@Import 导入的 bean 对象 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); // 清除掉已经解析处理过的配置类 configClasses.removeAll(alreadyParsed); // 判断读取器是否为空,如果为空的话,就创建完全填充好的 ConfigurationClass 实例的读取器 if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 核心方法,将完全填充好的ConfigurationClass实例转化为BeanDefinition注册入IOC容器 this.reader.loadBeanDefinitions(configClasses); // 添加到已经处理的集合中 alreadyParsed.addAll(configClasses); candidates.clear();
判断读取器 ConfigurationClassBeanDefinitionReader
实例是否为空,若为空的话,就创建完全填充好的 ConfigurationClass 实例的读取器
reader#loadBeanDefinitions
:核心方法,将完全填充好的 ConfigurationClass 实例转化为 BeanDefinition 注入 IOC 容器,循环遍历调用 loadBeanDefinitionsForConfigurationClass
方法
private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } // 若 bean 通过 @Import(ImportSelector) 方式添加到容器中的,那么此时 configClass#isImported 返回的是 true // configClass.importedBy 属性里面存储的是 ConfigurationClass 就是将 bean 导入的类 if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } // 判断当前 bean 是否含有 @Bean 注解方法,如果有,需要把这些方法产生 bean 放入到 BeanDefinitionMap 当中 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } // 将 @ImportResource 引入的资源注入 IOC 容器 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); // 如果 bean 上存在 @Import 注解,且 import 是一个实现了 ImportBeanDefinitionRegistrar 接口,则执行 ImportBeanDefinitionRegistrar#registerBeanDefinitions 方法 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
registerBeanDefinitionForImportedConfigurationClass 方法
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); // 定义 bd 实例 AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); // 设置 scope 属性以及通过生成器生成 beanName、公共的属性值信息 ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef); configBeanDef.setScope(scopeMetadata.getScopeName()); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); configClass.setBeanName(configBeanName); if (logger.isTraceEnabled()) { logger.trace("Registered bean definition for imported class '" + configBeanName + "'"); } }
处理被 @Import 导入的类,并且是没有加配置注解的【@Component、@Confuguration】否则会被先识别的配置类所替代,因为同样的配置类是只允许出现一个的
@Import 注解导入的类中如果不是 DeferredImportSelector 或 ImportBeanDefinitionRegistrar 这个类型的话,就会当作是一个普通的配置类进行 BeanDefinition 注入,importBy 属性值就是导入的类
loadBeanDefinitionsForBeanMethod 方法
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClass configClass = beanMethod.getConfigurationClass(); // 获取方法元数据 MethodMetadata metadata = beanMethod.getMetadata(); // 获取方法名称 String methodName = metadata.getMethodName(); // 是否标记为当前 @Bean 需要被跳过 if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) { configClass.skippedBeanMethods.add(methodName); return; } if (configClass.skippedBeanMethods.contains(methodName)) { return; } // 获取bean注解的属性 AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class); Assert.state(bean != null, "No @Bean annotation attributes"); // 获取别名 List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name"))); String beanName = (!names.isEmpty() ? names.remove(0) : methodName); for (String alias : names) { // 注册剩下的别名 this.registry.registerAlias(beanName, alias); } // 是否存在同名 bean 定义,这实际上已经覆盖之前(例如通过XML) if (isOverriddenByExistingDefinition(beanMethod, beanName)) { if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) { throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(), beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() + "' clashes with bean name for containing configuration class; please make those names unique!"); } return; } // 封装为ConfigurationClassBeanDefinition,表示是来自配置类里的bean定义 ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName); // 设置来源的类 beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); // 判断是否是静态的,设置 BeanClass if (metadata.isStatic()) { if (configClass.getMetadata() instanceof StandardAnnotationMetadata) { beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass()); } else { beanDef.setBeanClassName(configClass.getMetadata().getClassName()); } beanDef.setUniqueFactoryMethodName(methodName); } else { // instance @Bean method // 设置工厂名 beanDef.setFactoryBeanName(configClass.getBeanName()); beanDef.setUniqueFactoryMethodName(methodName); } // 如果方法元数据是标准方法元数据的话,就设置解析的工厂方法 if (metadata instanceof StandardMethodMetadata) { beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod()); } // 设置自定义装配模式,默认是构造器 beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); // 设置略过属性检查 beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor. SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // 处理通用注解,注解里可能还有自动装配注解 AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); // 获取自动装配枚举信息 Autowire autowire = bean.getEnum("autowire"); if (autowire.isAutowire()) { //如果是自动装配,也就是BY_NAME 或者 BY_TYPE,再设置了一次自动装配模式 beanDef.setAutowireMode(autowire.value()); } // 自动装配候选,默认是true boolean autowireCandidate = bean.getBoolean("autowireCandidate"); if (!autowireCandidate) { beanDef.setAutowireCandidate(false); } // 初始化方法 @PostConstruct、@PreDestroy 或 XML 或 InitializingBean、DisposableBean 接口 String initMethodName = bean.getString("initMethod"); if (StringUtils.hasText(initMethodName)) { beanDef.setInitMethodName(initMethodName); } // 销毁方法 String destroyMethodName = bean.getString("destroyMethod"); beanDef.setDestroyMethodName(destroyMethodName); // 处理作用域 ScopedProxyMode proxyMode = ScopedProxyMode.NO; AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class); if (attributes != null) { beanDef.setScope(attributes.getString("value")); proxyMode = attributes.getEnum("proxyMode"); if (proxyMode == ScopedProxyMode.DEFAULT) { proxyMode = ScopedProxyMode.NO; } } // 如果必要的话就替换原来 bean 定义与目标信息 BeanDefinition beanDefToRegister = beanDef; // 如果作用域不是no的话就要使用代理 if (proxyMode != ScopedProxyMode.NO) { BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy( new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS); beanDefToRegister = new ConfigurationClassBeanDefinition( (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName); } if (logger.isTraceEnabled()) { logger.trace(String.format("Registering bean definition for @Bean method %s.%s()", configClass.getMetadata().getClassName(), beanName)); } this.registry.registerBeanDefinition(beanName, beanDefToRegister); }
将 @Bean 注解方法元数据取出来分析,分析有没有别名、有没有跟 xml 配置冲突,封装成一个configurationClassBeanDefinition,然后设置工厂方法名,获取 bean 注解的属性,设置初始化方法,销毁方法,是否自动装配,是否需要代理等,最后将 BD 信息加入到 BeanDefinitionMap、BeanDefinitionNames 集合中
loadBeanDefinitionsFromImportedResources 方法
private void loadBeanDefinitionsFromImportedResources( Map<String, Class<? extends BeanDefinitionReader>> importedResources) { Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>(); importedResources.forEach((resource, readerClass) -> { // 选择默认的读取器类型 if (BeanDefinitionReader.class == readerClass) { if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) { // When clearly asking for Groovy, that's what they'll get... readerClass = GroovyBeanDefinitionReader.class; } else { // Primarily ".xml" files but for any other extension as well readerClass = XmlBeanDefinitionReader.class; } } BeanDefinitionReader reader = readerInstanceCache.get(readerClass); if (reader == null) { try { // 初始化 reader 读取器实例 reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry); // Delegate the current ResourceLoader to it if possible if (reader instanceof AbstractBeanDefinitionReader) { AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader); abdr.setResourceLoader(this.resourceLoader); abdr.setEnvironment(this.environment); } readerInstanceCache.put(readerClass, reader); } catch (Throwable ex) { throw new IllegalStateException( "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]"); } } // 该方法是 XML 方式注入 Bean 核心的解析工作步骤 reader.loadBeanDefinitions(resource); }); }
加载 ImportResources 中引入的 xml 文件,有两种加载类 GroovyBeanDefinitionReader、XmlBeanDefinitionReader,不指定默认采用的就是 XmlBeanDefinitionReader 读取器,然后用这个 reader 去加载 xml 资源,XmlBeanDefinitionReader#loadBeanDefinitions 核心方法博主在介绍 refresh 方法流程时有详细分析
ending
最后,还有一步保证措施需要执行,主要是为了检测 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
是否还有其他的配置类进行了引入
if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } // 如果有未解析的类,则将其添加到 candidates 中,这样 candidates 不为空,就会进入到下一次的 while 的循环中 for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; }
- 判断
registry.getBeanDefinitionCount() > candidateNames.length
目的:为了知道reader.loadBeanDefinitions(configClasses)
这一步有没有向 BeanDefinitionMap 中添加新的 BeanDefinition - 实际上就是看配置类,例如:AppConfig 类「Spring ImportTests 测试内部静态类」会向 BeanDefinitionMap 中添加 bean,这里的 AppConfig 类向容器中添加的 bean,实际上在
parser#parse 方法
这一步已经全部被解析好了,只是待塞入到 bdNames/bdMaps 集合中 - 如果有,registry.getBeanDefinitionCount 就会大于 candidateNames.length,这样就需要再次遍历新加入的 BeanDefinition,并判断这些 bean 是否已经被解析过了,如果未解析,需要重新进行解析
至此,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法已经全部分析完成
postProcessBeanFactory 内核心方法
该方法也是在 refresh 中 invokeBeanFactoryPostProcessors
方法会进行调用的,优先调用 BDRPP 接口 postProcessBeanDefinitionRegistry 方法,然后再调用 BFPP 接口 postProcessBeanFactory 方法
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor 钩子显然不支持 // 简单调用 processConfigurationClasses 懒加载在这一点上 processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } // 为满足条件的 @Configuration 注解标识的类进行动态代理,生成的代理对象 enhanceConfigurationClasses(beanFactory); // ImportAwareBeanPostProcessor 处理:对代理的配置类注入 BeanFactory,方便后续从该对象中获取到容器中的实例对象以及支持获取注解的元数据信息 beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }
从以上代码中可以看出,processConfigBeanDefinitions 方法在前面已经仔细分析过了,在这边主要介绍的核心方法就是 enhanceConfigurationClasses:对配置类生成代理子类,后续在获取 bean 实例时直接拦截调用,实现单例
enhanceConfigurationClasses 方法
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>(); for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE); MethodMetadata methodMetadata = null; if (beanDef instanceof AnnotatedBeanDefinition) { methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata(); } if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) { // // 配置类(full or lite)或配置类派生的 @Bean 方法,在这点上找到 bean 具体类型 AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef; if (!abd.hasBeanClass()) { try { abd.resolveBeanClass(this.beanClassLoader); } catch (Throwable ex) { throw new IllegalStateException( "Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } } } // 若 configurationClass 属性为 full,满足这个条件塞入到前面的集合中,后面的代码会对这个配置类进行代理增强处理 if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) { if (!(beanDef instanceof AbstractBeanDefinition)) { throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" + beanName + "' since it is not stored in an AbstractBeanDefinition subclass"); } else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) { logger.info("Cannot enhance @Configuration bean definition '" + beanName + "' since its singleton instance has been created too early. The typical cause " + "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " + "return type: Consider declaring such methods as 'static'."); } configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); } } // 没有需要增强的配置类,立即返回 if (configBeanDefs.isEmpty()) { return; } // 配置类动态代理增强的核心类 ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(); for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) { AbstractBeanDefinition beanDef = entry.getValue(); // 若 @Configuration 配置类被代理,就以目标类 CGLIB 进行代理增强 beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); // 为指定的配置类设置代理增强子类 Class<?> configClass = beanDef.getBeanClass(); Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader); if (configClass != enhancedClass) { if (logger.isTraceEnabled()) { logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " + "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); } } }
- 先获取到 BeanDefinition 信息 configurationClass 属性,若当前 BeanDefinition 未找到具体的类型,这边通过类加载器进行加载找到
- 判断该属性值是否等于
full
,若等于说明当前就是配置类,然后将其加入到待动态代理增强的集合中,该属性值如何设置的,下面再回顾一下:
// ConfigurationClassUtils#checkConfigurationClassCandidate 方法中 // proxyBeanMethods=true 就会设置为 full if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } // 若 bean 被 @Configuration 注解标注,且属性 proxyBeanMethods 为 false(使用代理模式),则将 bean 定义记为 lite else if (config != null || isConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; }
- 遍历待动态代理增强的集合,挨个元素进行动态代理实现,生成 CGLIB 动态代理类然后再覆盖到当前的 beanClass 属性,等类初始化、实例化时再进行创建
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) { if (EnhancedConfiguration.class.isAssignableFrom(configClass)) { if (logger.isDebugEnabled()) { logger.debug(String.format("Ignoring request to enhance %s as it has " + "already been enhanced. This usually indicates that more than one " + "ConfigurationClassPostProcessor has been registered (e.g. via " + "<context:annotation-config>). This is harmless, but you may " + "want check your configuration and remove one CCPP if possible", configClass.getName())); } return configClass; } // newEnhancer:创建 CGLIB 必备的 enhancer 实例设置好相关参数,createClass:注入实例 Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader)); if (logger.isTraceEnabled()) { logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s", configClass.getName(), enhancedClass.getName())); } return enhancedClass; } /** * 创建新的 CGLIB 实例 */ private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(configSuperClass); enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class}); enhancer.setUseFactory(false); // 名称生成策略器, enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 自定义的动态代理类生成策略 enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader)); // 回调拦截器类:BeanMethodInterceptor、BeanFactoryAwareMethodInterceptor,当调用配置类下方法时会被拦截处理逻辑 enhancer.setCallbackFilter(CALLBACK_FILTER); enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes()); return enhancer; }
动态代理类创建完成,等到 Bean 创建过程时再将这些配置类进行实例化,通过代理对象来调用实际方法的操作
如何确保 @Bean 单例
介绍 BeanMethodInterceptor 拦截器类具体的逻辑前,先解释在 Spring 中是如何确保 @Bean 方法标注的实例是单例存在的,因为 @Configuration 配置类被加载时会被动态代理进行增强,生成代理类,然后 @Bean 方法标注的实例就会经过 BeanMethodInterceptor 拦截器处理,拦截器逻辑内部会调用 beanFactory#getBean 方法,走正常 bean 创建和获取过程,所以在 spring 内部就确保了单例
但不一定所有的配置类 @Configuration 都会是代理类,@Configuration(proxyBeanMethods = false)
如果属性设置为 false,说明该配置类无须被代理,也就是它的 configurationClass 属性为 lite,那么它下面的 @Bean 方法也就不会是单例存在,示例代码如下:
@Configuration(proxyBeanMethods = false) public class DemoConfiguration { @Bean public Person person() { System.out.println(student()); System.out.println(student()); // 运行可以看出以上两个类地址不相同. return new Person(); } @Bean public Student student() { return new Student(); } }
普通的 @Component 注解下配置 @Bean 方法不会被代理,也就是说它在获取 bean method 实例时不会走正常 spring bean 获取过程,也就不存在单例了.
BeanMethodInterceptor#intercept 方法
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable { // 确定 bean 名称,不指定 name 属性默认就是用方法名作为 bean 名称 ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod); // 确认当前 bean 方法是否被 @Scope 注解所标注,设置是否需要被代理标识,若当前类正在创建,对 beanName 进行替换 if (BeanAnnotationHelper.isScopedProxy(beanMethod)) { String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName); if (beanFactory.isCurrentlyInCreation(scopedBeanName)) { beanName = scopedBeanName; } } // To handle the case of an inter-bean method reference, we must explicitly check the container for already cached instances. // 首先,检查 bean 是否为 FactoryBean,若是的话,先创建好实现该接口的实现类实例,resolveBeanReference 会再调用 getObject 方法返回具体的实例对象 if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanFactory, beanName)) { // 先创建 FactoryBean 接口的实例对象,再判断是属于那种类型 Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName); if (factoryBean instanceof ScopedProxyFactoryBean) { // 在前面的处理中对 @Bean 注解的方法进行了重新定义,如果 proxyMode 属性值不等于 DEFAULT 或 NO 情况下会对 BD 信息进行重新定义,class 就是 ScopedProxyFactoryBean // Scoped proxy factory beans are a special case and should not be further proxied } else { // 当前 @Bean 注入的类就是实现了 FactoryBean 接口的,在这里对其进行 CGLIB 代理增强后返回 return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); } } if (isCurrentlyInvokedFactoryMethod(beanMethod)) { // 工厂调用 bean 方法为了注册 bean 实例,实际上调用父类方法创建实例 // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually create the bean instance. if (logger.isInfoEnabled() && BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) { logger.info(String.format("@Bean method %s.%s is non-static and returns an object " + "assignable to Spring's BeanFactoryPostProcessor interface. This will " + "result in a failure to process annotations such as @Autowired, " + "@Resource and @PostConstruct within the method's declaring " + "@Configuration class. Add the 'static' modifier to this method to avoid " + "these container lifecycle issues; see @Bean javadoc for complete details.", beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName())); } return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); } // 会调用 beanFactory#getBean 方法从一级缓存中获取实例,此操作确保是单例的 return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); }
- 确认好 bean 名称,并确认当前 @Bean 修饰的方法是否被 @Scope 注解所修饰,设置标识,且进行判断当前修饰的 bean 实例是否正在创建,若当前类仍然在创建,就替换 bean 名称
- 检查 bean 是否为 FactoryBean 下接口的实例,包含它的子接口,如果是的话,先创建好该接口实现类的实例,主要是判断其是否为 ScopeProxyFactory 接口类型,如果是不作任何处理,该方法入口主要针对的就是 @Bean + @Scope 注解的逻辑处理,然后在最后一行代码 resolveBeanReference 方法中会调用 getObject 方法返回具体的实例对象
// 如果作用域不是no的话就要使用代理 if (proxyMode != ScopedProxyMode.NO) { // BeanDefinition 重新包装为 ScopedProxyFactoryBean 类型 BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy( new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS); beanDefToRegister = new ConfigurationClassBeanDefinition( (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName); }
- resolveBeanReference 方法最为重要,它里面的逻辑才是保证了 @Bean 实例实现单例的正确入口,beanFactory#getBean 进入到正常的 spring 创建过程,若一级缓存已经存在,就不会再次进行创建,当然,一切的前提都是 @Scope 注解的 scopeName 属性为
singleton
的情况下.
总结
该篇文章介绍了 Spring 核心类 ConfigurationClassPostProcessor 一些重要的方法,方法相关的源码也分析完毕,其中涉及到注解的解析,其实只要搞懂了 processConfigBeanDefinitions
方法里面的功能,自动装配的实现理解基本是就可以拿下了;同时,里面有针对性对每个 @Configuration 标注的配置类作了额外处理,是否进行了动态代理增强,来确保被 @Configuration 注解修饰的类下所有 @Bean 方法是否保持单例,这一切可以根据自己当前的业务使用场景来定义.
如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!
推荐专栏:Spring、MySQL,订阅一波不再迷路
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!