hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

spring源码进修(一)

2019-11-18杂谈搜奇网43°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源码的进修笔记还在延续更新哈。

 

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
spring源码进修(一)

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282048.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>