完全搞懂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);
	@Nullable
	String getParentName();

	 /**当前Bean对应的class名称**/
	void setBeanClassName(@Nullable String beanClassName);
	@Nullable
	String getBeanClassName();

	 /**当前bean的作用域**/
	void setScope(@Nullable String scope);
	@Nullable
	String getScope();

	 /**是否懒加载**/
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();

	 /**当前bean的依赖**/
	void setDependsOn(@Nullable String... dependsOn);
	@Nullable
	String[] getDependsOn();

   /**当bean被按类型注入到其他bean时,是否作为候选Bean**/
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();

 /**是否为主要bean,当前容器有多个当前类型的bean**/
	void setPrimary(boolean primary);
	boolean isPrimary();

   /**设置工厂Bean的名称**/
	void setFactoryBeanName(@Nullable String factoryBeanName);
	@Nullable
	String getFactoryBeanName();

   /**设置工厂bean中工厂方法的名称**/
	void setFactoryMethodName(@Nullable String factoryMethodName);
	@Nullable
	String 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的描述**/
	@Nullable
	String getDescription();
  /**bean资源文件的描述**/
	@Nullable
	String getResourceDescription();
 /**如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinitio**/
	@Nullable
	BeanDefinition 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());
	}


	@Override
	public final AnnotationMetadata getMetadata() {
		return this.metadata;
	}

	@Override
	@Nullable
	public 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;

	@Nullable
	private 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;
	}


	@Override
	public final AnnotationMetadata getMetadata() {
		 return this.metadata;
	}

	@Override
	@Nullable
	public final MethodMetadata getFactoryMethodMetadata() {
		return this.factoryMethodMetadata;
	}

}

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

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

@SpringBootApplication
public 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;
		}

		@Override
		public AnnotationMetadata getMetadata() {
			return this.annotationMetadata;
		}

		@Override
		public MethodMetadata getFactoryMethodMetadata() {
			return this.factoryMethodMetadata;
		}

		@Override
		public boolean isFactoryMethod(Method candidate) {
			return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));
		}

		@Override
		public 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.

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿老徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值