【Spring类路径Bean定义信息扫描】

1. ClassPathBeanDefinitionScanner作用

扫描类路径下的类注册为bean定义。

2. 类声明

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider
/**
 类名就是扫描类路径下bena定义。继承自类路径扫描候选组件提供器
 类路径扫描候选组件提供器的作用:
 	扫描类路径下的时候,使用过滤器是否考虑作为候选者,作为待注入的bean定义。
**/

3. 属性

	// beanDefinition注册器
	private final BeanDefinitionRegistry registry;
	
	// 存储默认的BeanDefinition属性值,如作用域(scope)、懒加载(lazy initialization)等设置。
	private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
	
	// 定义了一组字符串模式,用于决定哪些被扫描到的类应该被认为是自动装配候选者(autowire 	
	// candidates)。如果一个类的全限定名匹配这些模式之一,那么它将被视为可以进行自动装配的bean。
	private String[] autowireCandidatePatterns;

	// Bean名称生成器策略,默认是AnnotationBeanNameGenerator实例,它根据类上的注解或类名来生
	// 成bean的名称.在扫描和注册bean的过程中,会用到这个策略来生成唯一的bean名称。
	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
	
	// 指定了作用域元数据解析器,默认使用AnnotationScopeMetadataResolver,它根据类上的注解
	// (如@Component、@Service等)来确定bean的作用域(例如singleton或prototype)。
	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
	
	// 如果为true,表示在扫描过程中不仅会处理带有特定注解(如@Component、@Repository、@Service、
	// @Controller等)的类,还会处理类上的注解配置信息(如@Autowired、@Value等)。如果设置为
	//	false,则只扫描并注册类本身作为bean,而不处理注解驱动的配置。
	private boolean includeAnnotationConfig = true;

4. 构造器

/*
	单个参数的构造器: 传入注册器
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
	// 调用本地构造器: 注册器,使用默认过滤器
	this(registry, true);
}

/*
	双参数的构造器: 传入注册器, 是否使用默认过滤器
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
	// 调用本地构造器: 注册器, 是否使用默认的过滤器,获取或创建环境
	this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment) {
	// 调用本地构造器:注册器,过滤器,环境,资源加载器(null)
	this(registry, useDefaultFilters, environment,
			(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}

// 最终的构造器: 注册器、默认过滤器、环境、资源加载器
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	this.registry = registry;
	// 设置值
	if (useDefaultFilters) {
		registerDefaultFilters();
	}
	setEnvironment(environment);
	setResourceLoader(resourceLoader);
}

5. 扫描方法

// 扫描指定包的类
public int scan(String... basePackages) {
	// 获取当前注册器中bean定义的数量
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
	// 去扫描指定的包
	doScan(basePackages);
	
	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}
	// 返回注册后-之前已注册数量的差
	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

6. 真正扫描方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {
		// 查找候选组件
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		
		for (BeanDefinition candidate : candidates) {
			// 获取作用域
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			// 设置作用域
			candidate.setScope(scopeMetadata.getScopeName());
			// 按照beanName生成策略获取到bean名称
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			// 如果是抽象BeanDefinition
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			// 如果是注解BeanDefinition
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			// 检查给定的候选BeanDefinition,确定相应的BeanDefinition是否需要注册或者是否和
			// 已经存在的定义发生了冲突。
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);
			}
	}
}

补充一下:
AbstractBeanDefinition、AnnotatedBeanDefinition都是spring框架中定义和处理BeanDefinition的类,他们在SpringIOC容器的核心机制中有重要的地位。

  • 1. AbstractBeanDefinition:
    • 是个抽象类,实现了 BeanDefinition 接口,为BeanDefinition提供了一些通用的方法和属性。
    • 提供了BeanDefinition的基本结构,如作用域scope,初始化方法,销毁方法、依赖项管理等元数据信息的存储和操作
    • 子类有:RootBeanDefinition、GenericBeanDefinition
  • 2. AnnotatedBeanDefinition:
    • 该类封装了一个被注解标注的类的信息,并能够从类上的注解提取Bean的元数据,如作用域、生命周期回调方法等。
    • 在基于注解的配置环境下,Spring会使用 AnnotatedBeanDefinitionReader 或者 ClassPathBeanDefinitionScanner 等工具将带有注解的类转换为 AnnotatedBeanDefinition 对象并注册到IoC容器中。

7. postProcessBeanDefinition

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
	beanDefinition.applyDefaults(this.beanDefinitionDefaults);
		if (this.autowireCandidatePatterns != null) {
			beanDefinition.setAutowireCandidate(PatternMatchUtils.
						simpleMatch(this.autowireCandidatePatterns, beanName));
		}
}

8. 注册bean定义

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring通过扫描指定的包路径来查找bean定义,并将它们注册到应用程序上下文中。Spring使用`@ComponentScan`注解来指定需要扫描的包路径。当使用`@ComponentScan`注解时,Spring扫描所有被`@Component`、`@Service`、`@Repository`和`@Controller`注解的,并将它们注册为bean。 例如,以下代码演示了如何在Spring中使用`@ComponentScan`注解扫描名为`com.example`的包下的所有bean定义: ```java @Configuration @ComponentScan("com.example") public class AppConfig { // ... } ``` 除了`@ComponentScan`注解外,还可以使用`@Bean`注解手动注册bean,或者使用XML配置文件来定义bean。 ### 回答2: Spring框架通过Bean扫描机制可以自动检测和加载应用程序中的Bean。 Spring会在应用程序的路径扫描指定的包或,寻找被Spring管理的Bean。这个过程通常在应用程序启动时发生,Spring会搜索并加载符合条件的,并将其注册为Bean定义Spring框架提供了几种方式来配置Bean的扫描路径。 首先,可以通过使用@ComponentScan注解来开启Bean的自动扫描。在配置上加上@ComponentScan注解,并指定需要扫描的包路径Spring框架将会递归地扫描这些包,查找被@Component、@Service、@Repository、@Controller等注解修饰的,并将其注册为Bean。 其次,可以使用XML配置文件来进行扫描Bean。在配置文件中使用<context:component-scan>元素,并设置base-package属性为需要扫描的包路径Spring框架会自动扫描该包下所有被标记的,并加载注册为Bean。 除此之外,还可以使用基于Java的配置方式,通过编写配置定义Bean的扫描路径。在配置上使用@Configuration和@ComponentScan注解,指定需要扫描的包路径Spring框架会自动搜索并加载满足条件的。 总之,无论是通过注解还是XML配置文件,Spring框架可以通过不同的方式来扫描Bean,从而实现自动加载和注册。这样可以避免手动配置每个Bean的信息,提高开发效率,使应用程序更加灵活和可扩展。 ### 回答3: Spring框架通过使用不同的机制来扫描和注册bean。 首先,Spring可以通过基于XML的配置文件来扫描bean。在XML配置文件中,我们可以使用`<bean>`元素来定义一个bean,并通过`id`或`name`属性来标识它。通过在`<bean>`元素中配置适当的信息,如的全限定名、构造函数参数和属性值,Spring可以实例化和管理这些bean。然后,通过在XML配置文件中使用`<context:component-scan>`元素,可以使Spring自动扫描指定路径下的所有带有特定注解的,并将它们注册为bean。 其次,Spring还可以通过基于注解的方式来扫描bean。通过在上使用`@Component`注解或其派生注解(如`@Controller`、`@Service`、`@Repository`等),我们可以指示Spring将该注册为一个bean。同时,通过使用`@Autowired`注解,我们可以将其他依赖的bean自动注入到当前bean中,实现依赖注入的功能。在启动Spring应用程序时,Spring会自动扫描指定路径下的所有,并将被注解标记的注册为bean。 最后,Spring还支持自定义扫描和注册bean的机制。我们可以实现`BeanDefinitionRegistryPostProcessor`接口来编写自定义bean扫描器,通过编程方式将注册为bean。我们可以根据自己的需求定义扫描路径、过滤条件等,实现更加灵活的bean扫描和注册逻辑。 总结起来,Spring可以通过XML配置文件、基于注解的方式以及自定义扫描器等多种机制来扫描和注册bean,从而实现对应用程序中的组件的管理和控制。这些机制使开发人员能够以更加便捷和灵活的方式管理和使用bean。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值