> 文档中心 > 完全搞懂Spring的BeanDefintion和加载自定义BeanDefintion

完全搞懂Spring的BeanDefintion和加载自定义BeanDefintion


一、什么是BeanDefinition

  1. BeanDefinition描述了Bean的定义,包括该bean有哪些属性、构造函数参数、作用域、是否是抽象的等.
  2. 在Spring中是根据BeanDefinition来创建Bean的.
  3. BeanDefinition是Spring非常核心的概念.

1.1.BeanDefinition源码介绍

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {  /***常量定义***/  ...    /**父Definition名称设置**/void setParentName(@Nullable String parentName);@NullableString getParentName(); /**当前Bean对应的class名称**/void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName(); /**当前bean的作用域**/void setScope(@Nullable String scope);@NullableString getScope(); /**是否懒加载**/void setLazyInit(boolean lazyInit);boolean isLazyInit(); /**当前bean的依赖**/void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();   /**当bean被按类型注入到其他bean时,是否作为候选Bean**/void setAutowireCandidate(boolean autowireCandidate);boolean isAutowireCandidate(); /**是否为主要bean,当前容器有多个当前类型的bean**/void setPrimary(boolean primary);boolean isPrimary();   /**设置工厂Bean的名称**/void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();   /**设置工厂bean中工厂方法的名称**/void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName(); /**获取当前构造器参数**/ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !getConstructorArgumentValues().isEmpty();} /**获取当前bean的属性集合**/MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !getPropertyValues().isEmpty();} /**当前bean的作用域**/boolean isSingleton();boolean isPrototype(); /**当前Bean是否是抽象Bean**/boolean isAbstract(); /**当前bean的角色  int ROLE_APPLICATION = 0;  //用户自己定义的 Bean int ROLE_SUPPORT = 1;  //来源于配置文件的 Bean int ROLE_INFRASTRUCTURE = 2;//Spring 内部的 Bean **/int getRole(); /**bean的描述**/@NullableString getDescription();  /**bean资源文件的描述**/@NullableString getResourceDescription(); /**如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinitio**/@NullableBeanDefinition getOriginatingBeanDefinition();}

1.2.BeanDefinition体系介绍

在这里插入图片描述

1.2.1.BeanDefinition、AbstractBeanDefinition

BeanDefinition

bean定义接口,定义了Bean相关信息的设置、获取接口.

AbstractBeanDefinition

是所有具体的BeanDefinition的基类,定义了BeanDefinition的通用属性.

1.2.3.GenericBeanDefinition、ChildBeanDefinition、RootBeanDefinition

1.2.3.1.ChildBeanDefinition、RootBeanDefinition

ChildBeanDefinition

ChildBeanDefinition一般在Bean存在父子关系时,子类bean的BeanDefinition一般用该类型表示,但是从spring2.5开始,推荐使用GenericBeanDefinition.

RootBeanDefinition

根BeanDefinition,可以理解为Spring 运行时统一的Bean定义视图.如果一个Bean来源于多个多个原始Bean的定义,它在运行时会从这多个Bean定义抽出出来属性,生成一个RootBeanDefinition,该BeanDefintion不能设置parentName,因为它已经将parent相关的信息copy了过来,如果存在parent BeanDefinition的话.从spring 2.5以后,如果注册一个BeanDefinition推荐使用GenericeBeanDefinition

1.2.3.2.GenericBeanDefinition

GenericBeanDefinition is a one-stop shop for standard bean definition purposes.
  1. GenericBeanDefinition是用于标准bean定义的一站式格式.
  2. 可以选择性的指定构造函数参数值和类属性值,可以通过parentName设置父bean 的名称.
  3. 可以通过post-processor来处理该BeanDefinition,甚至可以重新配置父名称.

1.2.4.ScannedGenericBeanDefinition、AnnotatedGenericeBeanDefinition、ConfigurationClassBeanDefinition

1.2.4.1.ScannedGenericBeanDefinition

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {private final AnnotationMetadata metadata;/** * Create a new ScannedGenericBeanDefinition for the class that the * given MetadataReader describes. * @param metadataReader the MetadataReader for the scanned target class */public ScannedGenericBeanDefinition(MetadataReader metadataReader) {Assert.notNull(metadataReader, "MetadataReader must not be null");this.metadata = metadataReader.getAnnotationMetadata();setBeanClassName(this.metadata.getClassName());}@Overridepublic final AnnotationMetadata getMetadata() {return this.metadata;}@Override@Nullablepublic MethodMetadata getFactoryMethodMetadata() {return null;}}

通过类名我们也可以看出BeanDefintion和扫描类有关.

我们一般在spring应用中会配置扫描根路径,那么从该根路径下扫描到的@Controller、@Service、@Component等Bean定义的类,就会生成对应的ScannedGenericBeanDefinition.

从.class中获取Bean的配置元信息.

1.2.4.1.AnnotatedGenericeBeanDefinition

public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {private final AnnotationMetadata metadata;@Nullableprivate MethodMetadata factoryMethodMetadata;/** * Create a new AnnotatedGenericBeanDefinition for the given bean class. * @param beanClass the loaded bean class */public AnnotatedGenericBeanDefinition(Class<?> beanClass) {setBeanClass(beanClass);this.metadata = new StandardAnnotationMetadata(beanClass, true);}/** * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata, * allowing for ASM-based processing and avoidance of early loading of the bean class. * Note that this constructor is functionally equivalent to * {@link org.springframework.context.annotation.ScannedGenericBeanDefinition * ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a * bean was discovered specifically via component-scanning as opposed to other means. * @param metadata the annotation metadata for the bean class in question * @since 3.1.1 */public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {Assert.notNull(metadata, "AnnotationMetadata must not be null");if (metadata instanceof StandardAnnotationMetadata) {setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());}else {setBeanClassName(metadata.getClassName());}this.metadata = metadata;}/** * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata, * based on an annotated class and a factory method on that class. * @param metadata the annotation metadata for the bean class in question * @param factoryMethodMetadata metadata for the selected factory method * @since 4.1.1 */public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {this(metadata);Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");setFactoryMethodName(factoryMethodMetadata.getMethodName());this.factoryMethodMetadata = factoryMethodMetadata;}@Overridepublic final AnnotationMetadata getMetadata() { return this.metadata;}@Override@Nullablepublic final MethodMetadata getFactoryMethodMetadata() {return this.factoryMethodMetadata;}}

该类和ScannedGenericBeanDefinition有点类似,支持通过注解信息来生成BeanDefinition.

从在spring的应用中来看,是作为一个BeanDefintion定义文件的一个入口,类型xml,在SpringBoot中,我们一般会这样使用:

@SpringBootApplicationpublic class SpringMvcApp {    public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);    }}

那么SpringMvcApp这个类就会生成一个AnnotatedGenericBeanDefinition,然后获取当前spring应用bean扫描的路径等信息.

可以理解为一个入口类.

一般在ApplicationContext.refresh调用之前,注册到当前BeanRegistry中,然后在refresh过程中,会根据当前类的配置信息,初始化对应路径的bean.

1.2.4.1.ConfigurationClassBeanDefinition

private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {private final AnnotationMetadata annotationMetadata;private final MethodMetadata factoryMethodMetadata;public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {this.annotationMetadata = configClass.getMetadata();this.factoryMethodMetadata = beanMethodMetadata;setLenientConstructorResolution(false);}public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {super(original);this.annotationMetadata = configClass.getMetadata();this.factoryMethodMetadata = beanMethodMetadata;}private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {super(original);this.annotationMetadata = original.annotationMetadata;this.factoryMethodMetadata = original.factoryMethodMetadata;}@Overridepublic AnnotationMetadata getMetadata() {return this.annotationMetadata;}@Overridepublic MethodMetadata getFactoryMethodMetadata() {return this.factoryMethodMetadata;}@Overridepublic boolean isFactoryMethod(Method candidate) {return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));}@Overridepublic ConfigurationClassBeanDefinition cloneBeanDefinition() {return new ConfigurationClassBeanDefinition(this);}}

该类是@Configuration标记的类对应生成的BeanDefinition,会设置对应的工厂信息/工厂方法信息.

二、如何使用

我们现在已经了解了BeanDefinition的几种实现,那么我们如何动态的添加BeanDefintion到BeanFactory中.

2.1.ImportBeanDefinitionRegistrar+BeanDefinitionRegistryPostProcessor方式

我们从之前介绍@Configuration的文章可以知道,在解析@Configuration类时,会解析@Import 引入的ImportBeanDefinitionRegistrar的子类,并调用registerBeanDefinitions该方法.

在该方法中我们可以手动的注册BeanDefintion,那么我们可以在这里做以下操作.

  1. 可以注册一组BeanDefintion
  2. 可以注册一个BeanDefintion,但是该BeanDefinition对应的类实现了BeanDefinitionRegistryPostProcessor接口,这样在调用postProcessBeanDefinitionRegistry做一些根据当前注解元信息扫描类并加载到当前BeanDefinitionRegistry的操作.

mybatis-spring-boot-starter 的原理就是通过第二种方式实现.

我们简单看下:

MapperScan注解

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(MapperScannerRegistrar.class)@Repeatable(MapperScans.class)public @interface MapperScan 

MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {  /**   * {@inheritDoc}   *   * @deprecated Since 2.0.2, this method not used never.   */  @Override  @Deprecated  public void setResourceLoader(ResourceLoader resourceLoader) {    // NOP  }  /**   * {@inheritDoc}   */  @Override  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    AnnotationAttributes mapperScanAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));    if (mapperScanAttrs != null) {      registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,   generateBaseBeanName(importingClassMetadata, 0));    }  }  void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,      BeanDefinitionRegistry registry, String beanName) {    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);    builder.addPropertyValue("processPropertyPlaceHolders", true);    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");    if (!Annotation.class.equals(annotationClass)) {      builder.addPropertyValue("annotationClass", annotationClass);    }    Class<?> markerInterface = annoAttrs.getClass("markerInterface");    if (!Class.class.equals(markerInterface)) {      builder.addPropertyValue("markerInterface", markerInterface);    }    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");    if (!BeanNameGenerator.class.equals(generatorClass)) {      builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));    }    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {      builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);    }    String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");    if (StringUtils.hasText(sqlSessionTemplateRef)) {      builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));    }    String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");    if (StringUtils.hasText(sqlSessionFactoryRef)) {      builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));    }    List<String> basePackages = new ArrayList<>();    basePackages.addAll( Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText) .collect(Collectors.toList()));    basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName) .collect(Collectors.toList()));    if (basePackages.isEmpty()) {      basePackages.add(getDefaultBasePackage(annoMeta));    }    String lazyInitialization = annoAttrs.getString("lazyInitialization");    if (StringUtils.hasText(lazyInitialization)) {      builder.addPropertyValue("lazyInitialization", lazyInitialization);    }    String defaultScope = annoAttrs.getString("defaultScope");    if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {      builder.addPropertyValue("defaultScope", defaultScope);    }    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));    // for spring-native    builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());  }  private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {    return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;  }  private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {    return ClassUtils.getPackageName(importingClassMetadata.getClassName());  }  /**   * A {@link MapperScannerRegistrar} for {@link MapperScans}.   *   * @since 2.0.0   */  static class RepeatingRegistrar extends MapperScannerRegistrar {    /**     * {@inheritDoc}     */    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {      AnnotationAttributes mapperScansAttrs = AnnotationAttributes   .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));      if (mapperScansAttrs != null) { AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value"); for (int i = 0; i < annotations.length; i++) {   registerBeanDefinitions(importingClassMetadata, annotations[i], registry,generateBaseBeanName(importingClassMetadata, i)); }      }    }  }}

注册一个MapperScannerConfigurer类对应的BeanDefintion

MapperScannerConfigurer

public class MapperScannerConfigurer    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {...  @Override  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {    if (this.processPropertyPlaceHolders) {      processPropertyPlaceHolders();    }    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);    scanner.setAddToConfig(this.addToConfig);    scanner.setAnnotationClass(this.annotationClass);    scanner.setMarkerInterface(this.markerInterface);    scanner.setSqlSessionFactory(this.sqlSessionFactory);    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);    scanner.setResourceLoader(this.applicationContext);    scanner.setBeanNameGenerator(this.nameGenerator);    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);    if (StringUtils.hasText(lazyInitialization)) {      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));    }    if (StringUtils.hasText(defaultScope)) {      scanner.setDefaultScope(defaultScope);    }    scanner.registerFilters();    scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));  }...}

在AbstractApplicationContext.refresh的

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

阶段调用,扫描相关路径的class注册到BeanDefinitionRegistry.