SpringBoot中将@Bean方法解析为BeanDefinition详解
作者:流烟默
这篇文章主要介绍了SpringBoot中将@Bean方法解析为BeanDefinition详解,得到的BeanDefinition是ConfigurationClassBeanDefinition类型,会为BeanDefinition设置factoryMethodName,这意味着当实例化这个bean的时候将采用工厂方法,需要的朋友可以参考下
SpringBoot如何将@Bean方法注册为BeanDefinition
我们以MybatisPlusAutoConfiguration为例说明sqlSessionFactory()这个方法如何解析为BeanDefinition。
@Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { //... }
这个解析过程是在ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsForBeanMethod方法。
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClass configClass = beanMethod.getConfigurationClass(); MethodMetadata metadata = beanMethod.getMetadata(); //本文这里是sqlSessionFactory String methodName = metadata.getMethodName(); // Do we need to mark the bean as skipped by its condition? //判断是否需要跳过 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"); // Consider name and any aliases List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name"))); //尝试获取bean的名称,默认使用methodName String beanName = (!names.isEmpty() ? names.remove(0) : methodName); // Register aliases even when overridden //尝试注册别名 for (String alias : names) { this.registry.registerAlias(beanName, alias); } // Has this effectively been overridden before (e.g. via XML)? //校验BeanDefinition是否存在、是否允许覆盖 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 ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata); beanDef.setResource(configClass.getResource()); beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); //方法是否为静态方法 if (metadata.isStatic()) { // static @Bean method if (configClass.getMetadata() instanceof StandardAnnotationMetadata) { beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass()); } else { beanDef.setBeanClassName(configClass.getMetadata().getClassName()); } beanDef.setUniqueFactoryMethodName(methodName); } else { //实例方法,非静态方法 // instance @Bean method //设置FactoryBeanName,本文这里是 //com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration beanDef.setFactoryBeanName(configClass.getBeanName()); // 设置factoryMethodName 本文这里是sqlSessionFactory beanDef.setUniqueFactoryMethodName(methodName); } //本文这里跳过 这里是SimpleMethodMetadata if (metadata instanceof StandardMethodMetadata) { beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod()); } //设置注入标识 AUTOWIRE_CONSTRUCTOR=3 beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); //设置SKIP_REQUIRED_CHECK_ATTRIBUTE属性 beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor. SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); //BeanDefinition的通用后置处理,如Lazy、Primary、DependsOn、Role以及Description AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); //解析注解上配置的autowire Autowire autowire = bean.getEnum("autowire"); if (autowire.isAutowire()) { beanDef.setAutowireMode(autowire.value()); } //解析注解上配置的autowireCandidate boolean autowireCandidate = bean.getBoolean("autowireCandidate"); if (!autowireCandidate) { beanDef.setAutowireCandidate(false); } //解析注解上配置的initMethod String initMethodName = bean.getString("initMethod"); if (StringUtils.hasText(initMethodName)) { beanDef.setInitMethodName(initMethodName); } //解析注解上配置的destroyMethod String destroyMethodName = bean.getString("destroyMethod"); beanDef.setDestroyMethodName(destroyMethodName); // Consider scoping ScopedProxyMode proxyMode = ScopedProxyMode.NO; //获取@Scope注解信息 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; } } // Replace the original bean definition with the target one, if necessary BeanDefinition beanDefToRegister = beanDef; 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); } if (logger.isTraceEnabled()) { logger.trace(String.format("Registering bean definition for @Bean method %s.%s()", configClass.getMetadata().getClassName(), beanName)); } //注册BeanDefinition,beanName默认是methodName sqlSessionFactory this.registry.registerBeanDefinition(beanName, beanDefToRegister); }
方法流程如上所示,核心步骤都加了注释。这里要特别注意的是如下几点:
- 得到的BeanDefinition是ConfigurationClassBeanDefinition类型;
- 会为BeanDefinition设置factoryMethodName,这意味着当实例化这个bean的时候将采用工厂方法;
- 会区分方法是否为静态方法来设置BeanClass或者FactoryBeanName
这里得到的configClass
这里得到的MethodMetadata
最终得到的BeanDefinition属性
annotationMetadata = {SimpleAnnotationMetadata@5352} factoryMethodMetadata = {SimpleMethodMetadata@5635} decoratedDefinition = null qualifiedElement = null stale = false allowCaching = true isFactoryMethodUnique = true targetType = null resolvedTargetType = null isFactoryBean = null factoryMethodReturnType = null factoryMethodToIntrospect = null constructorArgumentLock = {Object@5823} resolvedConstructorOrFactoryMethod = null constructorArgumentsResolved = false resolvedConstructorArguments = null preparedConstructorArguments = null postProcessingLock = {Object@5824} postProcessed = false beforeInstantiationResolved = null externallyManagedConfigMembers = null externallyManagedInitMethods = null externallyManagedDestroyMethods = null beanClass = null scope = "" abstractFlag = false lazyInit = null autowireMode = 3 dependencyCheck = 0 dependsOn = null autowireCandidate = true primary = false qualifiers = {LinkedHashMap@5825} size = 0 instanceSupplier = null nonPublicAccessAllowed = true lenientConstructorResolution = false factoryBeanName = "com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration" factoryMethodName = "sqlSessionFactory" constructorArgumentValues = null propertyValues = null methodOverrides = {MethodOverrides@5826} initMethodName = null destroyMethodName = "(inferred)" enforceInitMethod = true enforceDestroyMethod = true synthetic = false role = 0 description = null resource = {ClassPathResource@5353} "class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]" source = {SimpleMethodMetadata@5635} attributes = {LinkedHashMap@5827} size = 1
到此这篇关于SpringBoot中将@Bean方法解析为BeanDefinition详解的文章就介绍到这了,更多相关@Bean方法解析为BeanDefinition内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!