Spring源码学习-IOC(注解扫描方式注册BeanDefinition)

本文介绍了Spring IOC自动扫描的基本用法,包括在配置文件和Java代码中开启自动扫描的方式,两种方式最终都通过ClassPathBeanDefinitionScanner的doScan()方法扫描注册bean定义。还进行了源码分析,如初始化时注册关键BeanDefinition,通过ASM库读取类和注解信息等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面讲了Spring IOC 的基本概念和xml配置方式怎么解析为BeanDefinition。感兴趣的可以去了解下 juejin.im/post/5cea6c…

1.基本用法

在一般情况下我们都会在spring配置文件中加入这么一段配置开启自动扫描。

	<context:component-scan base-package="com.study.mike.spring.service">
		<context:exclude-filter type="annotation" expression=""/>
		<context:include-filter type="annotation" expression=""/>
	</context:component-scan> 
复制代码

也可以用Java代码的形式开启自动扫描,第一种方式需要一个配置类并切加上@Configuration、@ComponentScan 这两个注解,第二种方式直接是你要扫描的包路径。两种方式注册BeanDefinition的时机有一点区别,但最终都是通过调用ClassPathBeanDefinitionScanner的doScan()方法扫描注册bean定义的。

@Configuration
@ComponentScan(basePackages="",includeFilters = { @Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class) })
public class ApplicationTest {
	public static void main(String[] args) {
		// 注解的方式1 
		ApplicationContext context1 = new AnnotationConfigApplicationContext(ApplicationTest.class);
		// 注解的方式2 
		ApplicationContext context2 = new AnnotationConfigApplicationContext("com.study.spring");
		CombatService cs2 = context2.getBean(CombatService.class);
		cs2.combating();
	}
    
}
复制代码

2.源码分析

1.初始化的时候都会调用默认无参构造器初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner,初始化 AnnotatedBeanDefinitionReader的时候会注册一些BeanFactoryPostProcessor(该接口的实现能够对BeanFactory再一次处理)类 型的BeanDefinition,这些Bean是spring能够通过注解加载bean的关键。下面是根据调用链画的流程图

最关键的代码在AnnotationConfigUtils中

/**
 * Register all relevant annotation post processors in the given registry.
 * @param registry the registry to operate on
 * @param source the configuration source element (already extracted)
 * that this registration was triggered from. May be {@code null}.
 * @return a Set of BeanDefinitionHolders, containing all bean definitions
 * that have actually been registered by this call
 */
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    //注册一些BeanFactoryPostProcessor类型的bean
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
	//前面说的两种方式的注册BeanDefinition时机的区别就在这,java类当配置类的方式通过该实例最终调用doscan()方法
	//进行注册(该实例的的调用时机在后面章节分析)。
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {//@Autowire注解 处理器
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {//JSR-250 注解支持
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {//JPA注解支持
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
            //事件监听
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}
复制代码

2.不管传入的参数是java配置类还是包路径,最终都会调用ClassPathBeanDefinitionScanner的doscan方法,下面看一代码

spring中通过ASM字节码操作库来读取类信息和注解信息,这里最关键的类是MetadataReader的实现类SimpleMetadataReader, 所有的操作都在这个类中处理。下面是调用关系

扫描方式注册Beandefinition的整个过程大致就是这样,如果对其中某一部分感兴趣的可以自己去调试一下,跟一下源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值