Spring 的beanDefinition

Spring 的beanDefinition

对于学习Spring而言,BeanDefinition是非常重要的,而且在Spring内部提供多种类型BeanDefinition,下边是Spring官网对BeanDefinition的描述

Within the container itself, these bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:

  • A package-qualified class name: typically, the actual implementation class of the bean being defined.
  • Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
  • References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
  • Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.

在这里插入图片描述
这里说明一下几个重要的类/接口:

  • ​ BeanDefnition:定义了一些基本常量和对BeanDefinition的基本操作方法

  • -AttributeAccessor:提供属性方法-

  • AttributeAccessorSupport:实现AttributeAccessor

  • GenericBeanDefinition:我们通过xml配置的bean class
    最终都会转换为这种类型的BeanDefninition,对于这种类型的BeanDefinition,它既可以作为Parent,
    也可以作为Child,在BeanDefinitoin中存在父子的说法,这个类好像是在Spring2.5以后提供的

  • ScannedGenericBeanDefintion:继承GenericBeanDefinition,
    我们通过@Component注解的类,最后都会转换为这种类型的BeanDefinition

  • AnnotatedGenericBeanDefinition:@Configuration标注的配置类将会被转换为这种类型的BeanDefintion

  • RootBeanDefinition:
    这种类型的BeanDefinition只能作为Parent出现,Spring自定义类最后都转换为这种类型的BeanDefinition,在最后实例化bean的时候,所有其他类型都会被转换为RootBeanDefinition

  • ChildBeanDefintion:这种类型的BeanDefinition只能作为Child出现

问题:如果同时提供@Component和xml配置, 这时候是什么类型BeanDefinition

​ 根据源码提供,Spring会先解析@CompontScan, 然后将对应包下的所有满足条件的类转换为ScannedGenericBeanDefintion,然后Spring会检查@ImportResource,这个时候会把xml配置文件中的class转换为GenericBeanDefinition, 如果在xml和注解中同时包含相同的类,最后会转换为ScannedGenericBeanDefintion

1.org.spring…由Spring提供

2.config为@Configuration标注的配置类

3.beanTest为@Component和xml同时配置的类

4.entity 为只有@Component标注的类

5.xmlBean为xml配置类
在这里插入图片描述

问题:为什么要定义这么多的BeanDefinition,只使用一种不好么?

个人认为,spring该开始也没有考虑这么多,最开始xml和注解类型没有留下的时候,可以通过一些简单的类就可以实现,但是随着这下新型技术出现,Spring也不得不跟上发展的步伐,但是原有的也不能彻底抛弃,所以就创建除了这么多不同的BeanDefinition,针对不同类型的BeanDefinition做不同类型的特殊处理,而且最后在实例化Bean的时候都还要合并成RootBeanDefinition

问题:怎么证明?

1.Spring内部提供的为RootBeanDefinition

​ 这是一段实例化BeanFactory的代码,可以看到内部使用spring自己提供的类被封装成了RootBeanDefinition

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		/**从传入的registry[也就是最开始创建的ApplicationContext, 这里是AnnotationConfigApplicationContext]
		 * 中获取到 beanFactory;
		 *
		 * 如果registry是DefaultListableBeanFactory的继承类, 则直接返回registry
		 * 如果是GenericApplicationContext,则将其强转为DefaultListableBeanFactory 返回
		 * 否则返回false
		 */
		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);

		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				//设置依赖比较器,什么时候会用到
				//处理时候过程的先后顺序, 主要处理@Order, 需要验证
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			//设置自动装配候选分解器,主要处理@Lazy和做@qualifier支持
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		//BeanDefinitionHolder 是BeanDefinition的持有类,
		/**
		 * BeanDefinitionHolder 提供用了如下属性
		 * private final BeanDefinition beanDefinition;
		 * private final String beanName;
		 * private final String[] aliases;
		 */
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		/**
		 * org.springframework.context.annotation.internalConfigurationAnnotationProcessor
		 * RootBeanDefinition spring内部自定义bean
		 * spring 拓展点之一
		 */
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		/**
		 * org.springframework.context.annotation.internalAutowiredAnnotationProcessor
		 */
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

2.@Configuration标注类被转换AnnotatedGenericBeanDefinition

​ 我们可以看到在源码中有这样一段,他在register(annotatedClasses);内部,所以源码证明了@Configuration被转换类AnnotatedGenericBeanDefinition

	private <T> void doRegisterBean(Class<T> annotatedClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		//实例化一个BeanDefinition
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        ....

3.entity 为只有@Component标注的类

查看Spring内部关于basePackage的扫描实现方法,可以知道ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); 所以标注注解被扫描处理的类最终会被转换为ScannedGenericBeanDefinition

	//扫描包, 获取到beanDefinition的class
	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			//凭借查询路径:classpath*:com/mjlf/spring/addBeantoContext/**/*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;

			//找到当前包下的所有类
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {

						//拿到metaDeata读取器
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						//比对排除过滤器和包含过滤器,判断该类是不是符合BeanDefinition候选条件
						if (isCandidateComponent(metadataReader)) {
							//将扫描出来, 当前的class生成为ScannedGenericBeanDefinition
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							//判断是否为候选组件,主要依据为是能实例化的类或者内部类,不能是抽象类或者接口, 如果是抽象类就必须标注@Lookup
							if (isCandidateComponent(sbd)) {//正常识别, 需要添加到beanDefinitionHolder中
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							} else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						} else {//不包含处理
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					} catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				} else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

5.xmlBean为xml配置类最后会被转换为GenericBeanDefinition

跟着源码可以发现,最终找到xml配置类型的最终会调用这个方法,方法内部使用:

GenericBeanDefinition bd = new GenericBeanDefinition();

	/**
	 * Create a new GenericBeanDefinition for the given parent name and class name,
	 * eagerly loading the bean class if a ClassLoader has been specified.
	 *
	 * xml解析最后会调用这个方法创建BeanDefinition, 所以默认xml配置的bean最后创建出来的BeanDefinition为GenericBeanDefinition
	 *
	 * @param parentName the name of the parent bean, if any
	 * @param className the name of the bean class, if any
	 * @param classLoader the ClassLoader to use for loading bean classes
	 * (can be {@code null} to just register bean classes by name)
	 * @return the bean definition
	 * @throws ClassNotFoundException if the bean class could not be loaded
	 */
	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

3.beanTest为@Component和xml同时配置的类

根据上边的描述,标注注解的会被转换为ScannedGenericBeanDefinition,而xml的会被转换为GenericBeanDefinition,那同时使用两种方法在同一个类上,spring是怎么处理的,我们知道parser.parse(candidates);方法调用用于扫描包,将符合条件的类转换为BeanDefinition,但是@ImportResource对应的xml配置文件是在this.reader.loadBeanDefinitions(configClasses);方法调用中处理的

do {
			//获取解析器[ConfigurationClassParser],主要负责扫描包, 然后将需要转换的class转换为BeanDefinition
			//很关键, 扫描指定包下的所有类,并将那些需要转换为BeanDefinition的类转换为BeanDefinition
			parser.parse(candidates);

			//验证,验证@Configuration的类???
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			//移除已经处理过的config
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}

			//获取configuration中@Bean这样的BeanDefinition
			//同时处理@Import,@ImportResource
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			//清除已经处理过的ConfigClass
			candidates.clear();
    ...
    
    /**
	 * Read {@code configurationModel}, registering bean definitions
	 * with the registry based on its contents.
	 */
	public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}
    
    
    /**
	 * Read a particular {@link ConfigurationClass}, registering bean definitions
	 * for the class itself and all of its {@link Bean} methods.
	 */
	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;
		}

		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//加载@Bean 标注的方法生成的BeanDefinition
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

//处理ImportResource
  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}


anMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

//处理ImportResource
  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章