Spring源碼學習-IOC(註解掃描方式註冊BeanDefinition)

前面講了Spring IOC 的基本概念和xml配置方式怎麼解析爲BeanDefinition。感興趣的能夠去了解下 juejin.im/post/5cea6c…java

1.基本用法

在通常狀況下咱們都會在spring配置文件中加入這麼一段配置開啓自動掃描。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定義的。express

@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的關鍵。下面是根據調用鏈畫的流程圖bash

最關鍵的代碼在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方法,下面看一代碼post

spring中經過ASM字節碼操做庫來讀取類信息和註解信息,這裏最關鍵的類是MetadataReader的實現類SimpleMetadataReader, 全部的操做都在這個類中處理。下面是調用關係ui

掃描方式註冊Beandefinition的整個過程大體就是這樣,若是對其中某一部分感興趣的能夠本身去調試一下,跟一下源碼。this

相關文章
相關標籤/搜索