您的位置:首页 > 编程语言 > Java开发

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

2017-05-07 00:00 1121 查看
摘要: spring源码学习之IOC实现原理(一)

作为一个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文件里写的相关内容放到这里,那么这个工厂其实已经可以正常工作了。
第一部分先到这里,更多东西还是接下去继续学习吧。好久没写作文了,逻辑有点乱,想到什么写什么,权当给自己做的一个总结吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring源码 IOC