IOC是用为用户建立、管理实例对象的。用户须要实例对象时只须要向IOC容器获取就好了,不用本身去建立,从而达到与具体类解耦。 php
简单点来说就是Spring IOC就是一个Map集合,对象的名字就是集合中的key,值就是对应的对象。咱们能够经过一个对象的名字到集合中获取对象。java
Spring提供了多种方式来配置Bean定义,有Xml,JavaConfigspring
Xml:设计模式
<bean id="user" class="com.ranger.bean.User">
<constructor-arg type="String" value="ranger"></constructor-arg>
<constructor-arg ref="cbean"></constructor-arg>
</bean>
<bean id="car" class="com.ranger.bean.Car">
<constructor-arg type="String" value="mazda"></constructor-arg>
</bean>
复制代码
JavaConfig的方法,这种方式要和注解配合app
@Configuration
public class AppConfig {
@Bean
public Service myService() {
return new ServiceImpl();
}
}
复制代码
建立SpringIOC容器的时候指定一个配置文件(xml),或者指定包扫描的路径(JavaConfig)ui
// 经过指定classpath下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml");
复制代码
或者使用JavaConfig的方式spa
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(AppConfig.class);
annotationConfigApplicationContext.refresh();
System.out.println(annotationConfigApplicationContext.getBean(User.class));
复制代码
大概介绍每一个父接口对应的职责prototype
ApplicationContext中定义的方法线程
ApplicationContext中定义了本身的几个方法,对这几个方法作简单的介绍:设计
咱们先从ApplicationContext后面的子孙开始
从上面的类继承图能够看出,AbastractApplicationContext 后面有两个儿子,分别是 GernericApplicationContext
和AbstractRefreshableApplicationContext
.这两个大儿子分别都持有了BeanFactory实例,这两个儿子全部的对于BeanDefiniton的注册,Bean的实例化都是基于这个BeanFactory实例的
它们分红了两大派系:
AbstractRefreshableApplicationContext:这个类在每次调用refresh方法的时候都会产生一个新的beanfactory实例(一般是,可是不是必须的)。这个应用上下文会经过一系列的配置文件去加载BeanDefinition。在调用refresh方法的时候才会建立内部持有的BeanFacoty实例(能够参见该类中的refreshBeanFactory方法)
GenericApplicationContext:这个类内部持有惟一的一个DefaultListableBeanFactory实例,并且相较于其它ApplicationContext的实现类,这个类在建立的时候就会有一个BeanFactory的实例,意思就是在refresh方法调用前,内部持有的BeanFactory实例就已经建立,且这个类从开始到最终都是一个BeanFacoty实例。
GenericApplicationContext实现了BeanDefinitionRegistry这个接口,这个接口干啥的呢,看名字是BeanDefinition的注册什么东东,没错,这个就是用来添加删除BeanDefiniton的。GenericApplicationContext也还有几个儿子,后面会简单分析一下他们的不一样。
上面都提到了refresh方法,这个方法是AbastractApplicationContext实现的,用于配置Context.该类使用了模板方法模式,不少方法都留给了子类去实现。
在AbstractApplicationContext中,实现了大多数ApplicationContext接口从BeanFactroy接口继承来的方法。
咱们还能够看到,AbstractApplicationContext的父类是ConfigurableApplicationContext,这个类提供了配置Context的方法,还提供了生命周期方法。
经过上面的分析咱们看到,虽然都有一个共同的祖先叫作ApplicationContext,可是不一样的子孙仍是有不一样的加载BeanDefinition的方法,可是其它方面都是同样的,SpringIOC中最重要的方法refresh就在他们共同的老爸AbstractApplicationContext中。refresh方法会根据BeanDefinition来建立Bean对象(除开lazy loading)
咱们就从咱们常见的ClasspathXmlApplicationContext开始分析:
如今项目中包含上面图中的类和配置,咱们编写一个主方法:
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml");
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
}
复制代码
springcontext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init="true" default-init-method="" default-destroy-method="">
<bean id="car" class="com.ranger.spring.ioc.bean.Car">
<constructor-arg name="brand" value="mazda"></constructor-arg>
</bean>
<bean id="person" class="com.ranger.spring.ioc.bean.Person">
<property name="car" ref="car"></property>
</bean>
</beans>
复制代码
调试启动Application类的main方法
由于最终BeanDefinition的注册都是在DefaultListableBeanFactory 中完成的,因此在registerBeanDefinition(String beanName, BeanDefinition beanDefinition)打断点就能看到下面的调用栈
从线程调用栈的下面向上看。
获得一个基本的流程:
这里面的解析Document获取BeanDefinition也比较复杂,若是有兴趣能够去看看。
那么GenericXmlApplicationContext加载BeanDefinition的流程是否是也和上面同样呢。
能够看到流程是同样的。
只是GenericXmlApplicationContext会先调用load来加载BeanDefinition,而后调用refresh完成配置。
而ClasspathXmlApplicationContext会在refresh方法调用的时候完成BeanDefinition的加载。
经过前面的分析咱们能够看到,ApplicationContext的大部分操做其实都是基于DefaultListableBeanFactory来完成的。
DefaultListableBeanFactory是BeanFactory的一个实现类
如今咱们来认识一下它:
经过读源码的doc,
这个接口是spring bean容器的根接口,它有一些为了提供特定功能的子接口ListableBeanFactory和ConfigurableBeanFactory
实现这个接口的对象持有一系列的 bean definitions,每一个bean definition 都有一个惟一的字符串名字。返回的Bean能够是单例的,也能够是独立的(每次都要建立),具体返回什么类型取决于applicationcontext的配置。
BeanFactory经过依赖注入来完成配置,一般的手段是用setter或者constructor
一般状况BeanFactory加载的BeanDefinition保存在一个配置资源中,好比XML文件。可是具体存储在哪儿是没有限制的,好比LDAP,XML,properties等等。
HierarchicalBeanFactory会先从本上下文找,找不到从父BeanFactory找,且本工厂实例中的bean会覆盖父工厂
BeanFactory的实现类应该尽量支持bean的生命周期方法,好比BeanNameAware,BeanClassLoaderAware,等等。
对于这些生命周期方法的支持,BeanFacoty没有给出抽象的接口,须要实现类本身去实现
BeanFactory的源码:
public interface BeanFactory {
// 用来区分FactoryBean和其产生的对象
String FACTORY_BEAN_PREFIX = "&";
// 经过BeanName获取Bean
Object getBean(String name) throws BeansException;
// 经过beanName和bean 的Class类型来获取Bean
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
// 增长获取bean的参数
Object getBean(String name, Object... args) throws BeansException;
// 经过类型获取
<T> T getBean(Class<T> requiredType) throws BeansException;
// 和上面同样的道理
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 判断是否包含某个Bean
boolean containsBean(String name);
// bean是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// bean是不是prototype
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//查询指定了名字的Bean的Class类型是否与指定类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
// 同上
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
//获取指定名字bean的Class类型
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 获取bean的别名
String[] getAliases(String name);
}
复制代码
BeanFactory 有三个子类接口:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory,还有一个实现类SimpleJndiBeanFactory。
这里对于BeanFactory的体系介绍就先不说了,太多了,单独写吧。
ApplicationContext的体系很大,重要抓住了核心几个比较重要的几个类:AbstractApplicationContext
,以及它的两个大儿子 GenericApplicationContext
和AbstractRefreshableApplicationContext
。大部分功能都在这里面实现了。
两个大儿子生下的儿子都是基于他们作了一些扩展。
阅读代码能够发现,ApplicationContext不少的方法都留到了子类去实现,这里用到了模板方法设计模式。
最终对于注册BeanDefinition和基于BeanDefinition建立bean实例都是归结到了DefaultListableBeanFactory中。
前面对Spring容器的体系作了总体的了解,接下来会分析bean的建立。