首先,本系列並非以介紹spring5 的新特性爲主,之因此以spring5爲標題,是由於即將賞析的源碼來自最新的spring版本.雖然說是spring最新版本,可是容器的整個生命週期與以前版本相比,並無很大的變化,咱們主要來看spring是如何一步步構建本身的容器,一步步將混亂不堪,錯綜複雜的依賴關係管理的層次分明,一步步組建本身的spring帝國.web
由於篇幅緣由,並不能在一篇博客中將全部spring容器的內容都介紹完成,所以,將分爲幾個部分分別介紹,本篇會先從最頂層瀏覽一下spring的一些容器,以及spring抽象出的容器的組裝過程,使咱們對spring容器有一個總體上的認知.spring
先來介紹spring中幾個重要的接口的做用:springboot
1.BeanFactory
2.BeanDefinition
3.BeanDefinitionRegistry
4.ApplicationContext
先看BeanFactory,這個接口定義了全部beanfactory基礎功能: 根據名稱獲取bean,獲取bean的類型/別名,判斷bean是否存在等,能夠看到,全部實現了這個接口的類,都具有這個功能.
BeanDefinition,定義了容器管理的對象.這個接口是整個spring的核心.BeanDefinition能夠看作spring的領域模型,它是對全部bean統一建模的產物,涵蓋了bean的全部信息,全部註冊進spring容器的bean均會被處理成各類beanDefinition的實現
存儲起來.
BeanDefinitionRegistry定義了beanDefinition的註冊功能.實現了這個接口的類,具有了註冊beandefinition的能力,將組裝好的beandefinition註冊到容器中。
最後看ApplicationContext,這個是容器的接口,全部容器均實現了這個接口,它定義了容器的基本功能:獲取容器名,獲取父容器,獲取beanfactory,註冊bean,等等,來看一下繼承關係:
咱們發現它繼承許多接口,這意味着實現這個接口的類,必須具有它所實現的全部類的功能,固然,這些功能正真實現的地方不會在application的實例中,這裏用到了代理模式(百度),將主要職責委託給其它實現接口的類去作,將調用者和實現者解耦,使代碼具有良好的擴展性。架構
spring的容器有多種,我把它分兩大類:應用類和web類。app
應用類中經常使用的幾個容器:函數
AnnotationConfigApplicationContext (主要是註解驅動,spring3.0之後加入)
GenericXmlApplicationContext (也是3.0之後加入的,能夠做爲下面兩種的替代。相對與相面兩個容器來講比較靈活,能夠靈活設置xml)
ClassPathXmlApplicationContext (和下面的容器基本同樣,一個是類路徑加載(主要特點是能加載jar中的xml文件),一個是文件路徑加載。二者實現基本同樣,因此會有GenericXmlApplicationContext的出現)
FileSystemXmlApplicationContext
web類的經常使用容器:
基本與上面一一對應,這裏就簡單列舉一些:
AnnotationConfigWebApplicationContext
GenericWebApplicationContext
XmlWebApplicationContext
瞭解上面的基本概念之後,咱們就要開始spring容器的探索之旅了,由於考慮到web容器還要考慮servlet版本,以及web.xml的配置,相對於應用容器來講稍微複雜一些。因此此次咱們並不會以支持web容器爲例去分析。
最近,springboot比較火爆(默認配置就是使用AnnotationConfigApplicationContext容器),咱們就來看看AnnotationConfigApplicationContext這個容器,看它是如何把一個個註解都轉化爲本身認識的bean並管理起來,
併爲咱們提供各類各樣的服務。(其實幾個容器的底層實現都同樣,畢竟是同一個爸生的。。。)
先看一個簡單的栗子:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(Level1Config.class); context.refresh(); Level2Component l = (Level3Component) context.getBean("level2Component");
l.asd();
@Configuration @ComponentScan("org.springframework.context.annotation.componentscan.level2") public class Level1Config { @Bean public TestBean level1Bean() { return new TestBean("level1Bean"); } }
@Component public class Level2Component { @Autowired SimpleComponent simpleComponent; public void asd(){ simpleComponent.testq(); } }
@Component public class SimpleComponent { public void testq(){ System.out.println("asdf"); } @Bean public String exampleBean() { return "example"; } }
這個栗子中,spring掃描了「org.springframework.context.annotation.componentscan.level2」包,裝載了裏面的Level2Component和SimpleComponent等,並將SimpleComponent實例化賦值給Level2Component,而後咱們就能夠經過context獲取到Level2Component的實例,並調用SimpleComponent的方法。工具
咱們看到從context的聲明到bean實例被調用,只通過了4行代碼,可謂簡單至極,但在這背後卻作了咱們想象不到的許多事。ui
在深刻源碼以前,咱們最好先從最頂層看一下它的架構,而後帶着問題去看,這樣纔能有目的性的找到答案和學到東西,廢話很少說,先看一下spring是如何裝配AnnotationConfigApplicationContext的,我的總結以下:this
準備 ——>初始化容器——>掃描裝配beanDefinition(這裏只是初步裝配)——>組裝實例化beanlua
所以,本系列也會分紅四部分和你們一塊兒來鑑賞各個流程的代碼。
這裏就先來介紹相對簡單的一步:準備。
準備階段,spring主要是爲容器初始化一些bean,將一些配置文件讀取,掃描器,beanfacotry,bean的一些默認處理工具類實例化並裝配起來,看一下構造函數:
public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
還有它父類的構造函數:
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); }
按照類初始化的順序,咱們能夠看到,這裏初始化了resourcePatternResolver,beanfactory,annotationBeanDefinitionReader,classPathBeanDefinitionScanner,這幾個類,這些類的做用分別是:資源定位解析,定義bean容器,註解類解析,類路徑資源掃描。它們的詳細實如今後續討論中依然會出現,這裏咱們只詳細關注AnnotationBeanDefinitionReader,這個類,由於這個類參與了準備階段的工做。
先看一下構造函數:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
ConditionEvaluator是@Conditional註解的解析的實現類,這裏咱們重點看
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
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<>(4); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { 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)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { 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)) { 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; }
在AnnotatedBeanDefinitionReader被實例化的時候spring洋洋灑灑註冊了一堆bean,這些bean將在之後咱們有新的bean加入的時候起關鍵性做用,好比改變bean的行爲,好比監聽發佈事件,好比解析一個外部定義的配置類,等等,這些bean在後面的分析中均會一一出現,這裏一樣不作全面介紹,咱們只要知道,這些bean實在這個時候就已經被spring裝載進來了。
咱們繼續往下看:
接着就是註冊咱們自定義的bean了.
public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); }
在咱們register配置類的時候reader(即AnnotationBeanDefinitionReader)的register方法會被調用,進而會調用它的doRegisterBean方法,將配置類注入容器中:
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(instanceSupplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } for (BeanDefinitionCustomizer customizer : definitionCustomizers) { customizer.customize(abd); } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
按照順序,首先咱們能夠看到,配置類會被放到AnnotatedGenericBeanDefinition中:
public AnnotatedGenericBeanDefinition(Class<?> beanClass) { setBeanClass(beanClass); this.metadata = new StandardAnnotationMetadata(beanClass, true); }
annotationGenericBeanDefinition實例會持有StandardAnnotationMetadata的實例,StandardAnnotationMetadata顧名思義,它是封裝了這個類的註解的元數據。接着,spring會判斷是否符合Condition註解的條件(spring4的加進來的一個註解),接下來會解析scope註解,來肯定這個bean的做用域,接下來會調用processCommonDefinitionAnnotations方法處理一些常規的註解:@Primary,@DependsOn,@Rule.@Description,並將這些信息放入定義好的beanDefinition中,接着經過BeanDefinitionReaderUtils將beanDefinition註冊到容器裏。至此算是容器中的第一個咱們本身的bean就註冊完成。
咱們看到,register方法實際上就是將配置類中一些咱們不長用註解信息解析並放入beandefinition中,將註解元數據放入StandardAnnotationMetadata中,由beanDefinition持有,最終把beanDefinition放入容器中(beanFactory),並無發生什麼不得了的事情,咱們定義的註解類也只是初步解析,並無進行掃描或者注入其它bean,事實上,在bean的準備階段,spring確實沒作多少事情,而是將一些十分重要的bean一一初始化進容器中,而咱們自定義的配置類就是其中之一。
好了,第一階段就到這裏。第一階段準備階段,spring實例化了一個reader,並在實例化過程當中裝載了annotationConfigApplicationContext容器特有的bean的處理邏輯,隨後把咱們的配置類也裝載進去變完成了準備階段的工做。
轉載請註明出處。