亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring中IoC源碼怎么寫

發布時間:2021-10-20 10:18:25 來源:億速云 閱讀:133 作者:柒染 欄目:大數據

本篇文章給大家分享的是有關Spring中IoC源碼怎么寫,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

一、 IoC 理論

IoC 全稱為 Inversion of Control,翻譯為 “控制反轉”,它還有一個別名為 DI(Dependency Injection),即依賴注入。

二、IoC方式

Spring為IoC提供了2種方式,一種是基于xml,另一種是基于注解。

  • <Bean>標簽來定義bean,進行管理。

  • @Bean注解來定義bean,進行管理。

本次文章我們就來分析下基于注解的IoC原理,在看文章之前我們可以帶一些疑問,這樣有助于我們更好的理解。

  1. @Bean是干什么用的?

  2. @Controller、@Service又是干啥的?

  3. @CompoentScan注解是怎么起作用的?

  4. Spring是怎么發現@Bean、@Controller、@Service這些注解修飾的類的?

  5. 發現之后是怎么注冊到IOC容器中的?

  6. IOC容器到底是個啥?

三、源碼分析

首先看下段代碼:

AnnotationConfigApplicationContext aac =
				new AnnotationConfigApplicationContext("com.mydemo");

AnnotationConfigApplicationContext可以實現基于Java的配置類(包括各種注解)加載Spring的應用上下文。避免使用application.xml進行配置。相比XML配置,更加便捷。

3.1、類結構圖

Spring中IoC源碼怎么寫 主要類或接口說明:

  • GenericApplicationContext——通用應用上下文,內部持有一個DefaultListableBeanFactory實例,這個類實現了BeanDefinitionRegistry接口,可以在它身上使用任意的bean definition讀取器。典型的使用案例是:通過BeanFactoryRegistry接口注冊bean definitions,然后調用refresh()方法來初始化那些帶有應用上下文語義(org.springframework.context.ApplicationContextAware)的bean,自動探測org.springframework.beans.factory.config.BeanFactoryPostProcessor等。

  • BeanDefinitionRegistry——用于持有像RootBeanDefinition和 ChildBeanDefinition實例的bean definitions的注冊表接口。DefaultListableBeanFactory實現了這個接口,因此可以通過相應的方法向beanFactory里面注冊bean。GenericApplicationContext內置一個DefaultListableBeanFactory實例,它對這個接口的實現實際上是通過調用這個實例的相應方法實現的。

  • AbstractApplicationContext——ApplicationContext接口的抽象實現,沒有強制規定配置的存儲類型,僅僅實現了通用的上下文功能。這個實現用到了模板方法設計模式,需要具體的子類來實現其抽象方法。自動通過registerBeanPostProcessors()方法注冊BeanFactoryPostProcessor, BeanPostProcessor和ApplicationListener的實例用來探測bean factory里的特殊bean——對比1分析

  • AnnotationConfigRegistry——注解配置注冊表。用于注解配置應用上下文的通用接口,擁有一個注冊配置類和掃描配置類的方法。

3.2 構造函數

        //默認構造函數,初始化一個空容器,容器不包含任何 Bean 信息,需要在稍后通過調用其register()
	//方法注冊配置類,并調用refresh()方法刷新容器,觸發容器對注解Bean的載入、解析和注冊過程
	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	
	public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	
	//最常用的構造函數,通過將涉及到的配置類傳遞給該構造函數,以實現將相應配置類中的Bean自動注冊到容器中
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		//調用無參構造函數,初始化AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner
		this();
		register(annotatedClasses);
		refresh();
	}

	
	//該構造函數會自動掃描以給定的包及其子包下的所有類,并自動識別所有的Spring Bean,將其注冊到容器中
	public AnnotationConfigApplicationContext(String... basePackages) {
	        //初始化ClassPathBeanDefinitionScanner和AnnotatedBeanDefinitionReader
		this();//step1
		//掃描包、注冊bean
		scan(basePackages);//step2
	        refresh();//step3
	}

主要屬性:

  • AnnotatedBeanDefinitionReader——BeanDefinition解析器用來解析帶注解的bean

  • ClassPathBeanDefinitionScanner——bean的掃描器 用來掃描類

  • 注冊解析傳入的配置類(使用類配置的方式進行解析)

  • 調用容器的refresh方法初始化容器

這里我們用的是最后一種構造函數,即傳入一個包路徑。

3.3 IoC 之 構造函數初始化

首先看step1,調用了本類的無參構造函數:

public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

然后初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
我們來看下ClassPathBeanDefinitionScanner的構造函數

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this(registry, true);
	}

繼續跟蹤下去,最后調用的是這個方法:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//為容器設置加載Bean定義的注冊器
		this.registry = registry;

		//是否使用默認過濾規則
		if (useDefaultFilters) {
			registerDefaultFilters();
		}
		//設置環境
		setEnvironment(environment);
		//為容器設置資源加載器
		setResourceLoader(resourceLoader);
	}

這里面最主要的是registerDefaultFilters()方法,初始化spring掃描默認過濾規則,對應@ComponentScan注解,如果沒有自定義規則,就初始化默認過濾規則。
這里調用的是ClassPathScanningCandidateComponentProvider類中的registerDefaultFilters()方法:

//向容器注冊過濾規則
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
	//向要包含的過濾規則中添加@Component注解類
	//@Service和@Controller都是Component,因為這些注解都添加了@Component注解
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	//獲取當前類的類加載器
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		//向要包含的過濾規則添加JavaEE6的@ManagedBean注解
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		//向要包含的過濾規則添加@Named注解
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

這里面有兩個關鍵變量:

  • private final List<TypeFilter> includeFilters = new LinkedList<>();

  • private final List<TypeFilter> excludeFilters = new LinkedList<>();

includeFilters表示要包含的注解,即只有包含includeFilters中的注解,才會被掃描
excludeFilters表示要排除的注解,即包含excludeFilters中的注解不會被掃描

在這個方法中,includeFilters集合中添加了@Component、JavaEE6的@ManagedBean和JSR-330的@Named注解
而excludeFilters集合沒做任何變動,即沒有要排除的注解

總結:
所以默認規則就是,只要包含了@Component、JavaEE6的@ManagedBean和JSR-330的@Named這3個注解中的任意一個,就會被掃描

以上就是Spring中IoC源碼怎么寫,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

靖西县| 抚松县| 开鲁县| 凯里市| 屯门区| 沙湾县| 邮箱| 申扎县| 贵州省| 桃源县| 临颍县| 溧阳市| 大同市| 长宁县| 嘉善县| 岗巴县| 常德市| 称多县| 韶山市| 文安县| 平和县| 巫山县| 涿州市| 通化市| 湘潭县| 汕头市| 洛扎县| 泾阳县| 当雄县| 涪陵区| 阳朔县| 东台市| 金湖县| 乌拉特后旗| 昌图县| 吉林省| 西青区| 琼海市| 牡丹江市| 出国| 大方县|