IoC 全稱爲 Inversion of Control,翻譯爲 「控制反轉」,它還有一個別名爲 DI(Dependency Injection),即依賴注入。java
Spring爲IoC提供了2種方式,一種是基於xml,另外一種是基於註解。spring
本次文章咱們就來分析下基於註解的IoC原理,在看文章以前咱們能夠帶一些疑問,這樣有助於咱們更好的理解。設計模式
首先看下段代碼:app
AnnotationConfigApplicationContext aac = new AnnotationConfigApplicationContext("com.mydemo");
AnnotationConfigApplicationContext能夠實現基於Java的配置類(包括各類註解)加載Spring的應用上下文。避免使用application.xml進行配置。相比XML配置,更加便捷。ide
主要類或接口說明:函數
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實例,它對這個接口的實現其實是經過調用這個實例的相應方法實現的。this
AbstractApplicationContext——ApplicationContext接口的抽象實現,沒有強制規定配置的存儲類型,僅僅實現了通用的上下文功能。這個實現用到了模板方法設計模式,須要具體的子類來實現其抽象方法。自動經過registerBeanPostProcessors()方法註冊BeanFactoryPostProcessor, BeanPostProcessor和ApplicationListener的實例用來探測bean factory裏的特殊bean——對比1分析.net
AnnotationConfigRegistry——註解配置註冊表。用於註解配置應用上下文的通用接口,擁有一個註冊配置類和掃描配置類的方法。翻譯
//默認構造函數,初始化一個空容器,容器不包含任何 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方法初始化容器
這裏咱們用的是最後一種構造函數,即傳入一個包路徑。
首先看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具體的包掃描過程Spring IoC 源碼分析 (基於註解) 之 包掃描