由于本人水平有限,本文内容较为简单,仅供个人学习笔记,或者大家参考,如果能够帮助大家,荣幸之至!本文主要分析AnnotationConfigApplicationContext实例化之后,到底干了那些事情。

  • 首先通过实例化applicationContext

  

  1. AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
  2.  
  3. AnnotationConfigApplicationContext.getBean("beanName");

分析:第一句实例化annotationConfigApplicationContext,初始化了spring的环境,第二句就可以从spring ioc容器中获取bean。

  • 接下来查看构造方法
  1. public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
  2. this();
  3. register(annotatedClasses);
  4. refresh();
  5. }
  • 分析:this()方法会先调用父类的构造函数,再调用当前类的默认构造方法,在父类的构造方法当中,实例化了DefaultListableBeanFactory对象,spring当中的默认工厂, 在当前类的构造函数当中实例化了一个reader和scanner。
  1. public GenericApplicationContext() {
  2. this.beanFactory = new DefaultListableBeanFactory();
  3. }
  • 这里的beanFactory很重要,后续实例化beanDefinition、beanName都存储在这里。
  1. this.reader = new AnnotatedBeanDefinitionReader(this);
  2. this.scanner = new ClassPathBeanDefinitionScanner(this);
  • reader用来读取被加了注解的beanDenition,以及在当前的构造函数当中,会实例化spring当中非常重要的五个beanPostProcessor(后续分析),以及一个beanFactory,在本文最后会对其分析。
  • scanner顾名思义是用来扫描的,只不过是提供外部程序员来调用的,spring内部并没有使用到。
  1. public void register(Class<?>... annotatedClasses) {
  2. Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
  3. this.reader.register(annotatedClasses);
  4. }
  • 这里的register方法就是调用了我们在构造函数当中初始化的reader,来完成注册beanDenifition。这里注册的类参数是一个数组,通过for循环来处理。注册一个bean之后需要调用refresh()方法,来完成实例化。如果注册了Appconfig类的话,如果不调用refresh()方法,项目会报错,如果注册的是普通的bean,在通过getBean来获取的时候,底层方法会手动调用refresh()当中的方法。接下来我们看register()当中的方法。
  1. <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
  2. @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
  3. AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
  4. if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
  5. return;
  6. }
  7. abd.setInstanceSupplier(instanceSupplier);
  8. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  9. abd.setScope(scopeMetadata.getScopeName());
  10. String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
  11. AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  12. if (qualifiers != null) {
  13. for (Class<? extends Annotation> qualifier : qualifiers) {
  14. if (Primary.class == qualifier) {
  15. abd.setPrimary(true);
  16. }
  17. else if (Lazy.class == qualifier) {
  18. abd.setLazyInit(true);
  19. }
  20. else {
  21. abd.addQualifier(new AutowireCandidateQualifier(qualifier));
  22. }
  23. }
  24. }
  25. for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
  26. customizer.customize(abd);
  27. }
  28.  
  29. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  30.  
  31. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  32.  
  33. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  34. }
  • 分析:首先会判断是否跳过解析,如果元数据为null,或者没有加condition注解则返回false。因为该beanDenifition是初始化new出来的,所以元数据永远不会为空。接下来获取bean的作用域范围,默认是单例,生成beanName,接下来解析类的通用注解,比如说lazy,primary,description等等注解。处理限定符注解,还有自定义注解。beanDefinitionHolder主要是为了传值,在注册beanDenifition时候可以少传一个参数。这里传的这几个参数永远为null,比如@Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers,所以不用解析,如果我们想要解析,只能获取到reader对象,手动调用传参数给他。
  1.           // Still in startup registration phase
  2. this.beanDefinitionMap.put(beanName, beanDefinition);
  3. this.beanDefinitionNames.add(beanName);
  4. this.manualSingletonNames.remove(beanName);
  • map当中存储key:beanName,value:beanDefinition,beanDefinitionName集合当中存储所有的beanDenifitionName。
  1. // Register aliases for bean name, if any.
  2. String[] aliases = definitionHolder.getAliases();
  3. if (aliases != null) {
  4. for (String alias : aliases) {
  5. registry.registerAlias(beanName, alias);
  6. }
  7. }
  • 源码当中处理类的别名,spring当中如果设置了别名,可以通过id或者别名从spring容器当中获取类的实例。

接下来查看最后一个refresh方法,spring当中的bean生命周期,就是从这里开始的

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. prepareRefresh();
  5.  
  6. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  7.  
  8. // Prepare the bean factory for use in this context.
  9. prepareBeanFactory(beanFactory);
  10.  
  11. try {
  12. // Allows post-processing of the bean factory in context subclasses.
  13.  
  14. postProcessBeanFactory(beanFactory);
  15.  
  16. // Invoke factory processors registered as beans in the context.
  17. invokeBeanFactoryPostProcessors(beanFactory);
  18.  
  19. // Register bean processors that intercept bean creation.
  20. registerBeanPostProcessors(beanFactory);
  21.  
  22. // Initialize message source for this context.
  23. initMessageSource();
  24.  
  25. // Initialize event multicaster for this context.
  26.  
  27. initApplicationEventMulticaster();
  28.  
  29. // Initialize other special beans in specific context subclasses.
  30. onRefresh();
  31.  
  32. // Check for listener beans and register them.
  33. registerListeners();
  34.  
  35. // Instantiate all remaining (non-lazy-init) singletons.
  36. finishBeanFactoryInitialization(beanFactory);
  37.  
  38. // Last step: publish corresponding event.
  39. finishRefresh();
  40. }
  41.  
  42. catch (BeansException ex) {
  43. if (logger.isWarnEnabled()) {
  44. logger.warn("Exception encountered during context initialization - " +
  45. "cancelling refresh attempt: " + ex);
  46. }
  47.  
  48. // Destroy already created singletons to avoid dangling resources.
  49. destroyBeans();
  50.  
  51. // Reset 'active' flag.
  52. cancelRefresh(ex);
  53.  
  54. // Propagate exception to caller.
  55. throw ex;
  56. }
  57.  
  58. finally {
  59. // Reset common introspection caches in Spring's core, since we
  60. // might not ever need metadata for singleton beans anymore...
  61. resetCommonCaches();
  62. }
  63. }
  64. }

分析:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();获取我们的beanFactory,bean的生命周期就是从这里开始的,prepareBeanFactory顾名思义准备beanfactory,包括设置类加载器、解析器(解析类似与el表达式的页面语句,由spring提供的)、属性编辑器(spring boot当中的yml配置)、这里最重要的是添加了一个BeanPostProcessor,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));来看这里做了什么事情!

  1. class ApplicationContextAwareProcessor implements BeanPostProcessor

该类继承自BeanPostProcessor,实现了这两个方法

  1. @Nullable
  2. default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  3. return bean;
  4. }
  5. @Nullable
  6. default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  7. return bean;
  8. }

缓存预热之时,我们会使用@PostConstruct注解初始化init()方法,在构造函数之后执行,@preDestroy在销毁之后执行。后置处理器spring提供给我们的扩展点,这两个方法会在init方法的前后执行,spring当中的AOP也是这样来完成对IOC的加强的,已经把bean暴漏出来了,在这里返回代理对象即可。接下来看ApplicationContextAwareProcessor实现后置处理器做了那些事情。

  1. @Override
  2. @Nullable
  3. public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
  4. AccessControlContext acc = null;
  5.  
  6. if (System.getSecurityManager() != null &&
  7. (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
  8. bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
  9. bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
  10. acc = this.applicationContext.getBeanFactory().getAccessControlContext();
  11. }
  12.  
  13. if (acc != null) {
  14. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  15. invokeAwareInterfaces(bean);
  16. return null;
  17. }, acc);
  18. }
  19. else {
  20. invokeAwareInterfaces(bean);
  21. }
  22.  
  23. return bean;
  24. }
  25.  
  26. private void invokeAwareInterfaces(Object bean) {
  27. if (bean instanceof Aware) {
  28. if (bean instanceof EnvironmentAware) {
  29.  
  30. ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
  31. }
  32. if (bean instanceof EmbeddedValueResolverAware) {
  33. ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  34. }
  35. if (bean instanceof ResourceLoaderAware) {
  36. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  37. }
  38. if (bean instanceof ApplicationEventPublisherAware) {
  39. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  40. }
  41. if (bean instanceof MessageSourceAware) {
  42. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  43. }
  44. if (bean instanceof ApplicationContextAware) {
  45. if (!bean.getClass().getSimpleName().equals("IndexDao"))
  46. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  47. }
  48. }
  49. }

分析:这里主要判断是否实现了ApplicationContextAware接口,如果实现了,就把applicationContext注入给他。此时就可以解释为什么实现了applicationcontext接口,重写set方法,就可以获取applicationContext,解决单例模式下获取原型对象了。关于spring当中的其他后置处理器,会在后续文章中更新!

spring源码学习(一)的更多相关文章

  1. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  2. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  3. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  4. Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md

    写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...

  5. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  6. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  7. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

  8. 【目录】Spring 源码学习

    [目录]Spring 源码学习 jwfy 关注 2018.01.31 19:57* 字数 896 阅读 152评论 0喜欢 9 用来记录自己学习spring源码的一些心得和体会以及相关功能的实现原理, ...

  9. Spring 源码学习——Aop

    Spring 源码学习--Aop 什么是 AOP 以下是百度百科的解释:AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程通过预编译的方式和运行期动态代理实 ...

  10. Spring 源码学习 04:初始化容器与 DefaultListableBeanFactory

    前言 在前一篇文章:创建 IoC 容器的几种方式中,介绍了四种方式,这里以 AnnotationConfigApplicationContext 为例,跟进代码,看看 IoC 的启动流程. 入口 从 ...

随机推荐

  1. docker设置引用国内镜像加速

    设置步骤: 1 先到daocloud.io网站注册一个账号 过程略,注册成功后,进入控制台 2 点击控制台上的加速器 拉到中间部分,有一个『主机监控程序』的文字链接,见下图: 然后选择主机类型,我用的 ...

  2. 初探APT 攻击

    作者:joe       所属团队:Arctic Shell 本文编写参考: https://www.freebuf.com/vuls/175280.html https://www.freebuf. ...

  3. java使用memcached1--安装与基本使用

    环境 CentOs6.4 libevent-2.0.22-stable memcached-1.4.24 一.memcached安装 # cd /usr/local 1.编译安装libevent # ...

  4. mybatis常用默认配置

    设置参数 描述 有效值 默认值 cacheEnable 该配置影响所有映射器中配置的缓存全局开关 true.false true lazyLoadingEnable 延迟加载的全局开关.当它开启时,所 ...

  5. SpringMvc渲染视图

    这篇博文讨论的问题是从ModelAndView如何渲染到页面. 首先要知道每个请求处理完之后都会返回一个ModelAndView对象. 这里我分6种情况来分析,代表6种返回类型: ModelAndVi ...

  6. 确定 RN 中方法的 queue

     如果不指定,每一个模块,都会生成自己的一个串行队列. 可以通过强行声明一个队列来指定所有方法都在这个队列执行 - (dispatch_queue_t)methodQueue { return di ...

  7. Python-Django编程问题汇总

    OS:Windows10 64 IDE:JetBrain Python Community Edition 2017.3.4 Python:python-3.6.4 Django:V2.0.3 问题一 ...

  8. javascript如何阻止事件冒泡和默认行为

    阻止冒泡:    冒泡简单的举例来说,儿子知道了一个秘密消息,它告诉了爸爸,爸爸知道了又告诉了爷爷,一级级传递从而以引起事件的混乱,而阻止冒泡就是不让儿子告诉爸爸,爸爸自然不会告诉爷爷.下面的demo ...

  9. jQuery 事件注册

    重点事件注册.on() <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset= ...

  10. 平衡树 替罪羊树(Scapegoat Tree)

    替罪羊树(Scapegoat Tree) 入门模板题 洛谷oj P3369 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入xx数 删除xx数(若有多个相同 ...