Spring
中提供了基於註解來配置bean
的容器,即AnnotationConfigApplicationContextjava
先看看在Spring家族中,AnnotationConfigApplicationContext
在一個什麼樣的地位,看看繼承圖spring
能夠看到Spring
提供了基於Xml
配置的容器以外,還提供了基於註解和Groovy
的容器,今天咱們來看看基於註解配置的容器緩存
看看AnnotationConfigApplicationContext
中提供了哪些方法app
咱們從構造方法開始,分析基於註解的容器,是如何獲取BeanDefinition
並註冊beanDefinitionMap
中的函數
public AnnotationConfigApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); }
接下來一步一步分析下去post
調用了本類中的一個無參構造函數ui
public AnnotationConfigApplicationContext() { //註解bean讀取器 this.reader = new AnnotatedBeanDefinitionReader(this); //註解bean掃描器 this.scanner = new ClassPathBeanDefinitionScanner(this); }
而AnnotationConfigApplicationContext
繼承自GenericApplicationContext
,因此GenericApplicationContext
的無參構造方法也會被調用this
/** * Create a new GenericApplicationContext. * @see #registerBeanDefinition * @see #refresh */ public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
能夠看到父類拆功能鍵spa
public void scan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); this.scanner.scan(basePackages); }
調用了scanner.scan()
,scanner
是ClassPathBeanDefinitionScanner
的一個實例code
/** * Perform a scan within the specified base packages. * @param basePackages the packages to check for annotated classes * @return number of beans registered */ public int scan(String... basePackages) { // 原來的beanDefinition數量 int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); doScan(basePackages); // 下面是註冊配置處理器 // 這個是啥呢,就是之前在xml中配置的<context:annotation-config> // 這裏會註冊四個註解處理器,分別是 // AutowiredAnnotationBeanPostProcessor, // CommonAnnotationBeanPostProcessor // PersistenceAnnotationBeanPostProcessor // RequiredAnnotationBeanPostProcessor // 這四個都是BeanPostProccessor,在每一個Bean建立的時候都會調用它們 // 既然是註解處理器,他們處理什麼註解呢? // AutowiredAnnotationBeanPostProcessor 處理@AutoWired註解 // CommonAnnotationBeanPostProcessor 處理@ Resource 、@ PostConstruct、@ PreDestroy // PersistenceAnnotationBeanPostProcessor 處理@PersistenceContext // RequiredAnnotationBeanPostProcessor 處理@Required // Register annotation config processors, if necessary. if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } // 返回本次掃描註冊的beanDefinition數量 return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart); }
這個ClassPathBeanDefinitionScanner
是幹什麼的呢,經過查看源碼註釋
/ * A bean definition scanner that detects bean candidates on the classpath, * registering corresponding bean definitions with a given registry ({@code BeanFactory} * or {@code ApplicationContext}). * * <p>Candidate classes are detected through configurable type filters. The * default filters include classes that are annotated with Spring's * {@link org.springframework.stereotype.Component @Component}, * {@link org.springframework.stereotype.Repository @Repository}, * {@link org.springframework.stereotype.Service @Service}, or * {@link org.springframework.stereotype.Controller @Controller} stereotype. */
意思就是掃描類路徑下的被@Component
,@Repository
,@Service
,@Controller
註解的的類,而後註冊BeanDefinition
到給定的BeanFactory
重點戲就在doScan()
方法中
/** * Perform a scan within the specified base packages, * returning the registered bean definitions. * 掃描指定的包,反正註冊後的Bean Definition * <p>This method does <i>not</i> register an annotation config processor * but rather leaves this up to the caller. * 這個方法不會註冊註解處理器,而是留給調用者去作這件事 * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); // 遍歷給定的packages for (String basePackage : basePackages) { // findCandidateComponents是獲取一個包下的知足條件的類,下面會介紹 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
findCandidateComponents(String basePackage)
這個方法能夠獲取一個包下的知足條件的BeanDefinition
/** * Scan the class path for candidate components. * @param basePackage the package to check for annotated classes * @return a corresponding Set of autodetected bean definitions */ public Set<BeanDefinition> findCandidateComponents(String basePackage) { // 是否使用Filter,不掃描指定的包 if (this.componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { // 掃描包 return scanCandidateComponents(basePackage); } }
這個scanCandidateComponents()
裏面就是獲取資源判斷是否知足條件,可是Spring
判斷的條件比較複雜,就先不看了
再回到doScan()
方法裏面:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); // 遍歷給定的packages for (String basePackage : basePackages) { // findCandidateComponents是獲取一個包下的知足條件的類,下面會介紹 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { // 綁定scope(解析@Scope) ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 設置beanName String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } ////檢查beanName否存在 if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 正式將BeanDefinition注入 registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
registerBeanDefinition(definitionHolder,registry)
/** * Register the specified bean with the given registry. * <p>Can be overridden in subclasses, e.g. to adapt the registration * process or to register further bean definitions for each scanned bean. * @param definitionHolder the bean definition plus bean name for the bean * @param registry the BeanDefinitionRegistry to register the bean with */ protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); }
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. // 以主要名稱 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. // 若是有別名,遍歷別名註冊到容器的aliasMap String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
上面的registry.registerBeanDefinition()
就是DefaultListableBeanFactory
中的方法了
如今scan()
方法已經走完了,回到構造方法中,還剩最後一個refresh()
這裏的refresh
和Xml
的容器中調用的refresh
是同一個方法,都來自AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 記錄啓動時間,標記狀態,檢查變量 prepareRefresh(); // 初始化BeanFactory容器 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 添加BeanPostProcessor,手動註冊幾個特殊的 bean prepareBeanFactory(beanFactory); try { // 子類擴展點 postProcessBeanFactory(beanFactory); // 調用 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 註冊 BeanPostProcessor 的實現類 registerBeanPostProcessors(beanFactory); // 初始化MessageSource initMessageSource(); // 初始化事件廣播器 initApplicationEventMulticaster(); // 子類擴展點 onRefresh(); // 註冊事件監聽器 registerListeners(); // 初始化全部的 singleton beans finishBeanFactoryInitialization(beanFactory); // 完成refresh(),發佈廣播事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 銷燬已經初始化的的Bean destroyBeans(); // 設置 active爲false cancelRefresh(ex); throw ex; } finally { // 清除緩存 resetCommonCaches(); } } }
這裏也有一點不一樣就是第二步obtainFreshBeanFactory()
,這個方法裏面的調用getBeanFactory
是留給子類實現的,基於註解的AnnotationConfigApplicationContext
和ClassPathXmlApplicationContext
是不同的。
具體就是調用refresh
方法屢次,AnnotationConfigApplicationContext
類的BeanFactory
始終都是同一個,不會從新建立,可是ClassPathXmlApplicationContext
會從新建立