文档章节

spring源码学习之IOC实现原理(一)

 热心市民王先生
发布于 2017/05/07 22:43
字数 1407
阅读 78
收藏 1

作为一个java程序员,感觉自己日常开发用的最多的框架就是spring了,在使用的同时不得不感叹spring的强大功能,几乎像一个万花筒,什么玩意都能集成进去,所以打算好好研究下spring的源码,但是拖延症一直阻碍着我,最近下定决心开始做起来。
    说道spring,最核心的无非就是IOC和AOP了,所以就从这俩哥们开始学习吧。IOC是spring最核心的理念,包括AOP也要屈居第二,那么IOC到底是什么呢?四个字,控制反转。  网上有不少是这么解释IOC的,说IOC是将对象的创建和依赖关系交给容器,这句话相信不少人都知道,在我个人的理解,IOC就是让我们的开发变的更简单了,为什么?不用自己去new一个对象了。
上代码看看

public class Person {  
  
    public void who(){  
        System.out.println("i am programmer");  
    }  
}

Person类是一个经常需要用到的对象,做为程序眼工作还需要一个地点Company类

public class Company {  
  
    public Person person;  
      
    public Company(Person person){  
        this.person = person;  
    }  
      
    public void work(){  
        person.who();  
        System.out.println("I am working in company");  
    }  
} 

OK,这就是我们没有spring的情况下,对公司注入一个程序员的做法。 有了spring该怎么做呢?

public class Company {  
  
    @Autowired  
    public Person person;  
      
    public void work(){  
        person.who();  
        System.out.println("I am working in company");  
    }  
} 

有了spring之后,注入对象简单清晰明了,当然这只是最简单的一种依赖情况,实际工作中还会有更复杂的依赖情况,2层、3层甚至N层,这就更能体现出IOC的好处了。除了注解还有XML的形式,这里就不多废话了,具体可以去看其他资料。
下面正式开始学习IOC的源码实现
spring的包很多,但是IOC实现无论千变万化都离不开两个最基本的接口BeanFactory、BeanDefinition。 首先来看BeanFactory的源码

public interface BeanFactory {  
   ......
   
    Object getBean(String name) throws BeansException;  
   
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;  
   
    <T> T getBean(Class<T> requiredType) throws BeansException;  
   
    Object getBean(String name, Object... args) throws BeansException;  
......
  
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;  

......
  
} 

删掉了一部分源码,太长占地方,其他部分可以在源码文件里看到根据名字应该很容易理解其作用。这个类是spring中所有bean工厂,也就是IOC容器的基本接口,所有IOC容器都只是它的实现或者为了满足特别需求的扩展实现,其中包括平时用的最多的ApplicationContext。可以看出,这些工厂的实现最大的作用就是根据bean的名称或者类型等等,来返回一个bean的实例。
但是如果我们要实例化一个对象除了知道对象的名字或者类型就可以了吗?难道是工厂对象中有一个Map<String,Object>,我们根据key来获取value吗?很显然不是,因为spring的初始化是可以控制的,通过lazy-init属性的设置,可以到用的时候才将bean实例化供开发者使用。
所以我们必须知道这个对象的定义、它的依赖关系(就像company依赖了person),不然就无法实例化了。那么这时候就又出现一个新的接口BeanDefinition

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {  
    ......
    String[] getDependsOn(); 
    ......
    void setDependsOn(String[] dependsOn);  
    ......
}

这个便是spring中的bean定义接口,IOC容器工厂里持有的bean定义,就是他的实现类和子接口。仔细观看,能发现beanDefinition中有两个方法分别是String[] getDependsOn()和void setDependsOn(String[] dependsOn),这两个方法就是获取依赖的beanName和设置依赖的beanName,所以只要我们有一个BeanDefinition,就可以产生一个完整的bean实例。
那么知道了上述两个接口,大致已经猜到spring是如何做的了。就是让bean工厂持有一个Map<String,BeanDefinition>,这样就可以在任何时候我们想用哪个bean,取到它的bean定义,我们就可以创造出一个新鲜的实例。
BeanFactory是接口不能持有这样一个对象,那么这个对象一定是在BeanFactory的某个实现类或者抽象实现类当中所持有的。这个类就是DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory  
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {  
    ......
    private String serializationId;  
  
    private boolean allowBeanDefinitionOverriding = true;  
  
    private boolean allowEagerClassLoading = true;  
  
    private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();  
  
    private final Map<Class, Object> resolvableDependencies = new HashMap<Class, Object>();  

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();  

    private final List<String> beanDefinitionNames = new ArrayList<String>();  
  
    private boolean configurationFrozen = false;  
  
    private String[] frozenBeanDefinitionNames;  
  
 ......
} 

这里同样省略了N多源码。通过名字应该能看出来这是个默认的bean工厂实现类。这个实现类提供了最简单的情况下的实现,而以后如果想要对spring的容器扩展,那么只需要扩展或者持有这个对象即可。

final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

从这里,应该能确定的确是让BeanFactory的某个实现类持有bean定义的MAP对象,采用beanName作为key值。简单的说就是bean工厂的初始化其实就是往这个Map里填充东西。所以只要我们将注解扫描到的或者XML文件里写的相关内容放到这里,那么这个工厂其实已经可以正常工作了。 第一部分先到这里,更多东西还是接下去继续学习吧。好久没写作文了,逻辑有点乱,想到什么写什么,权当给自己做的一个总结吧

© 著作权归作者所有

粉丝 1
博文 2
码字总数 1922
作品 0
杭州
程序员
私信 提问
那些年,我们一起追的Spring

学无止境,但仍需及时总结。 自去年开始写作以来,写了一些关于Spring的文章,今天将它们汇总起来,一方面方便大家阅读,另一方面,也是一次小的复盘总结。 IOC 首先是Spring的IOC,也就是控...

SexyCode
2018/08/14
0
0
三条路线告诉你如何掌握Spring IoC容器的核心原理

一、前言 前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一...

Java小铺
2018/08/27
0
0
面试阿里等互联网公司java岗位时,关于Spring到底需要掌握什么?

之前分享过一些BAT面试必会的文章,一些读者看了,问过我,Spring 这篇需要掌握一些什么?相信这个问题也是很多读者心中的疑问,今天就来聊一下关于 Spring,我从面试中收获的一些经验。 一....

别打我会飞
04/17
0
0
向Spring大佬低头——大量源码流出解析

用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文...

Java团长17
2018/07/11
0
0
Spring IOC 容器源码分析系列文章导读

1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本。经过十几年的迭代,现在的 Spring 框架已经非常成熟了。Spring 包含了众多模块,包括但不限于...

coolblog
2018/05/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

0.01-Win10安装linux子系统

一、安装Debian子系统 -1、控制面板设置: -1.1、打开“控制面板” —— “程序” —— “启用或关闭Windows功能” —— 勾选 “适用于Linux的Windows子系统” -2、设置: -2.1、打开“设置”...

静以修身2025
昨天
1
0
init 0-6 (启动级别:init 0,1,2,3,4,5,6)

启动级别: init 0,1,2,3,4,5,6 这是个很久的知识点了,只是自己一直都迷迷糊糊的,今天在翻出来好好理解下。。 0: 停机 1:单用户形式,只root进行维护 2:多用户,不能使用net file system...

圣洁之子
昨天
2
0
Android Camera HAL浅析

1、Camera成像原理介绍 Camera工作流程图 Camera的成像原理可以简单概括如下: 景物(SCENE)通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为电信号,经过A/D(模数转...

天王盖地虎626
昨天
2
0
聊聊Elasticsearch的ProcessProbe

序 本文主要研究一下Elasticsearch的ProcessProbe ProcessProbe elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java public class ProcessProb......

go4it
昨天
2
0
mysql PL(procedure language)流程控制语句

在MySQL中,常见的过程式SQL语句可以用在存储体中。其中包括IF语句、CASE语句、LOOP语句、WHILE语句、ITERATE语句和LEAVE语句,它们可以进行流程控制。 IF语句相当于Java中的if()...else if(...

edison_kwok
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部