spring源码进修(一)
2019-11-18杂谈搜奇网51°c
A+ A-近来在进修spring源码,把本身的进修笔记纪录一下,分享出来,假如有明白错的,也愿望各位能提出来,人人一同进修
起首spring源码的进口要领:
1 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { 2 //在this()中挪用父类的要领 建立了 DefaultListableBeanFactory(这就是寻常说的springbean工场) 3 this(); 4 //把annotatedClasses(AppConfig.java)放到spring容器中,最底层挪用的是DefautListableBeanFactory.registerBeanDefinition()要领,将设置类put到beanDefinitionMap中 5 register(annotatedClasses); 6 refresh(); 7 } 8 9 //这个要领是this()挪用的 10 public AnnotationConfigApplicationContext() { 11 /** 12 * 建立一个读取注解的bean定义读取器 13 * bean定义实在就是beanDefinition 14 * 在这个要领内里 声清楚明了六个比较主要的bean,并将这个几个bean存到了beanDefinitionMap内里 15 * CommonAnnotationBeanPostProcessor 16 * RequiredAnnotationBeanPostProcessor 17 * AutowiredAnnotationBeanPostProcessor 18 * ConfigurationClassPostProcessor 19 */ 20 this.reader = new AnnotatedBeanDefinitionReader(this); 21 /** 22 * 实际上完成包扫描并非这里的scanner完成的。而是spring在扫描包的时刻,又从新new了一个ClassPathBeanDefinitionScanner完成的 23 * 这里的scanner是为了程序员能够在外部挪用annotationConfigApplicationbContext对象 24 */ 25 this.scanner = new ClassPathBeanDefinitionScanner(this); 26 }
在spring初始化过程当中,最主要的要领就是refresh()要领,在refresh中完成了bean的扫描、初始化、以及AOP动态代办对象的生成等等,我们来一点一点剖析
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 // Prepare this context for refreshing. 4 //预备事情包括设置启动时候、是不是激活标志位、初始化属性源设置 5 prepareRefresh(); 6 7 // Tell the subclass to refresh the internal bean factory. 8 //返回一个factory 9 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 10 11 // Prepare the bean factory for use in this context. 12 //预备工场 13 prepareBeanFactory(beanFactory); 14 15 try { 16 // Allows post-processing of the bean factory in context subclasses. 17 postProcessBeanFactory(beanFactory); 18 19 // Invoke factory processors registered as beans in the context. 20 /** 21 * TODO 22 * 完成对bean的扫描,将beanDefinition存到map中 23 * 24 26 * 27 * 在这个要领中,注入bean,分为了三种 28 * 一、一般bean:@Component注解的bean30 * 31 * 1.猎取到一切的beanFactoryPostProcessor 32 * 2.实行 bean后置处置惩罚器的postProcessBeanFactory(configurationClassPostProcessor),该要领会把beanFactory作为入参传到要领内里 33 * 3.从beanFactory中猎取到一切的beanName 打断点看一下 org.springframework.context.annotation .ConfigurationClassPostProcessor#processConfigBeanDefinitions 34 * 35 * 4.然后将一切的bean包装成beanDefinitionHolder,在后面又依据beanName和bean的metadata包装成了ConfigurationClass 36 * 5.把一切包括@ComponentScan的类取出来,遍历每一个componentScan,挪用 ClassPathBeanDefinitionScanner.doScan(basePackages)要领 37 * 6.在doScan要领中,会遍历basePackages,因为一个ComponentScan中能够设置多个要扫描的包 38 * 7.猎取每一个包下面的 *.class文件,registerBeanDefinition(definitionHolder, this.registry); 这个要领底层就是挪用org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition要领 把当前bean put到beanDefinitionMap中 39 * 40 * 二、是经由过程ImportSelector注解注入的bean 41 * 42 * 三、ImportBeanDefinitionRegistrar注入的bean 43 */ 44 invokeBeanFactoryPostProcessors(beanFactory); 45 46 // Register bean processors that intercept bean creation. 47 //注册beanPostProcessor;要领内里挪用的是 beanFactory.addBeanPostProcessor(postProcessor); 48 registerBeanPostProcessors(beanFactory); 49 50 // Initialize message source for this context. 51 initMessageSource(); 52 53 // Initialize event multicaster for this context. 54 /** 55 * 注册一个多事宜派发器 56 * 先从beanFactory猎取,假如没有,就建立一个,并将建立的派发器放到beanFactory中 57 */ 58 initApplicationEventMulticaster(); 59 60 // Initialize other special beans in specific context subclasses. 61 onRefresh(); 62 63 // Check for listener beans and register them. 64 /** 65 * 注册一切的事宜监听器 66 * 将容器中的时候监听器添加到 applicationEventMulticaster 中 67 */ 68 69 registerListeners(); 70 71 // Instantiate all remaining (non-lazy-init) singletons. 72 /** 73 * TODO 74 * 完成对bean的实例化 75 */ 76 finishBeanFactoryInitialization(beanFactory); 77 78 // Last step: publish corresponding event. 79 /** 80 * 当容器革新完成以后,发送容器革新完成事宜 81 * publishEvent(new ContextRefreshedEvent(this)); 82 */ 83 finishRefresh(); 84 } 85 86 catch (BeansException ex) { 87 88 } 89 90 finally { 91 // Reset common introspection caches in Spring's core, since we 92 // might not ever need metadata for singleton beans anymore... 93 resetCommonCaches(); 94 } 95 } 96 }
在refresh要领中,个人以为比较主要的是
invokeBeanFactoryPostProcessors(beanFactory);
finishBeanFactoryInitialization(beanFactory);
其他几个要领,还没来得及举行深切的研讨,本次主要来剖析这两个要领
起首说,一个bean要在spring中完成初始化,简朴来讲,分为两步(当前,这是个人现在的明白)
1.起首要把bean扫描到容器中,然后再将bean实例化;invokeBeanFactoryPostProcessors这个要领个人明白:主如果完成了bean的扫描,将要注入的bean扫描到beanDefinitionMap中;这个map是用来寄存
spring中要实例化的bean,key值是beanName,value值是一个beanDefinition对象,beanDefinition寄存的是对bean的一些形貌信息;
2.当bean被扫描到beanDefinitionMap中以后,就须要挪用bean的组织要领等来实例化,然后在挪用bean的初始化要领来举行初始化;以及bean的属性注入等;这个事情是在finishBeanFactoryInitialization要领中完成;
一、
我们起首来讲在invokeBeanFactoryPostProcessors要领中是怎样完成bean的扫描的;
先说结论吧:spring在将bean注入到容器中,有几种体式格局:
1.@Component注解+@ComponeneScan注解
2.@Import注解注入,import注入的话分两种,一种是注入ImportSelector,一种是注入ImportBeanDefinitionRegistrar
3.@Bean 在设置类中,直接经由过程该注解将bean注入到容器中
1.那我们起首来讲@Component注解这类注入体式格局的源码:
因为这里的挪用链比较长,所以直接截图放出来,不一个一个手打了;
在前面,spring将设置类注入到了beanDefinitionMap中,在这个要领内里,会猎取到设置类;
然后猎取到设置类的ComponentScan注解的值,因为ComponentScan能够指定多个包,所以会轮回每一个包,在doScan要领中猎取到当前包下一切的*.class文件;将扫描的文件,put到beanDefinitionMap中
这是经由过程扫描注入bean的体式格局道理
2.那经由过程ImportSelector和importBeanDefinitionRegistrar体式格局注入的bean,是如许注入的
org.springframework.context.annotation.ConfigurationClassParser#processImports
在这个要领中完成了对这两种体式格局注入的bean的扫描;要领中,会辨别是ImportSelector.class照样ImportBeanDefinitionRegistrar.class;
轻微说一下这两个接口的区分:
①.ImportSelector接口中selectImports要领返回的是一个String[] 数组对象,返回数组中,包括的是要注入的bean的全类名
②.ImportBeanDefinitionRegistrar接口中的要领能够直接注册bean,因为接口中的要领能够获得BeanDefinitionRegisty对象
我们接着说注入:关于ImportSelector注入的bean会存入到configurationClasses中;关于ibdr(importbeanDefinitionRegistrar)注入的bean会存到importBeanDefinitionRegistrars中
在处置惩罚完这些以后,在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions要领中,对import注入的bean和@Bean注入的bean举行注入
1 private void loadBeanDefinitionsForConfigurationClass( 2 ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { 3 4 if (trackedConditionEvaluator.shouldSkip(configClass)) { 5 String beanName = configClass.getBeanName(); 6 if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { 7 this.registry.removeBeanDefinition(beanName); 8 } 9 this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); 10 return; 11 } 12 13 //这里是对importSelector注入的bean举行初始化 14 if (configClass.isImported()) { 15 registerBeanDefinitionForImportedConfigurationClass(configClass); 16 } 17 18 //@Bean 注解须要注入的bean对象 19 for (BeanMethod beanMethod : configClass.getBeanMethods()) { 20 loadBeanDefinitionsForBeanMethod(beanMethod); 21 } 22 23 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); 24 //这里是对ImportBeanDefinitionRegistrar注入的bean举行初始化 25 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); 26 }
这个要领实行完以后,一切的bean就被注入到了beanDefinitionMap中
在invokebeanFactoryPostProcessors要领中,另有许多细节,比如对设置类上加@Configuration注解与不加@Configuration注解的处置惩罚,对importSelector注入bean的递归挪用等等。,假如展开了,不知道该怎样写,细节点太多,太碎,所以本次只把骨干流程简朴说了一下,关于源码解读的解释,能够参考本人在GitHub上传的解释来看。https://github.com/mapy95/spring-sourceCode
这上面是spring的源码进修的一些解释,关于spring源码的进修笔记还在延续更新哈。