1.通过SpringApplication.run方法进入查看源码,会发现代码中下面的这段代码创建了IOC容器。
context = createApplicationContext();
跟进去找到下面这段代码,spring boot创建了AnnotationConfigApplicationContext类的Class信息,并且实例化,赋值给context。后面的一系列操作都会依托这个类,所以该类是本文分析的重点。
contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS)
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
2. 下面是AnnotationConfigApplicationContext类的类图,我们可以看到AnnotationConfigApplicationContext类具备非常多接口和类的功能,下面就自顶向下逐个分析各个接口的作用。
3.BeanFactory接口
String FACTORY_BEAN_PREFIX = "&";
//根据名称得到bean实例
Object getBean(String name) throws BeansException;
//根据名称和类型得到bean实例,类型可为基类
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
//根据名称和构造函数参数获取bean实例
Object getBean(String name, Object... args) throws BeansException;
//根据类型获取bean实例,类型可以为基类,如果有大于一个的实例则会抛出异常
<T> T getBean(Class<T> requiredType) throws BeansException;
//根据类型和构造函数参数获取bean实例
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
//根据名称判断是否包含bean
boolean containsBean(String name);
//根据名称判断bean是否为单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//根据名称判断bean是否为原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//根据名称和可解析类型进行匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
//根据名称和类信息进行匹配
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
//根据名称得到类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//根据名称获取别名
String[] getAliases(String name);
BeanFactory是最基本的容器,唯一的属性定义了FactoryBean的前缀。该接口的含义即为:只要实现了BeanFactory接口的类,都可以读取IOC容器中的bean,但是容器中的bean从哪里来呢?答案是通过实现Registry接口来具备注册bean的功能。
4.下面看一下BeanFactory的子接口——ListableBeanFactory。
//查看当前容器是否包含beanName对应的BeanDefinition
boolean containsBeanDefinition(String beanName);
//查看容器中Bean定义的总数
int getBeanDefinitionCount();
//查看容器中所有BeanDefinition的名称
String[] getBeanDefinitionNames();
//根据可解析类型得到所有Bean的名称
String[] getBeanNamesForType(ResolvableType type);
//根据类型得到所有Bean的名称
String[] getBeanNamesForType(Class<?> type);
//根据类型得到所有Bean的名称,includeNonSingletons含义为是否包含原型实例,
//allowEagerInit含义为是否将懒加载的实例立即初始化
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
//根据类型得到bean实例的Map,key为bean的name
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
//根据类型、是否包含非单例、是否立即初始化懒加载的类,得到相应的bean实例,key为bean的name
<T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
//找到所有标注了相应注解类型且未被初始化的bean实例的名称
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
//根据注解类型得到所有标注了该注解的bean实例,key为bean的name,value为bean实例
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
//根据bean的名称和注解类型找到相应的注解,如果实例bean上没有相应的注解则会抛错
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException;
该接口主要是提供了bean的批量读取的功能,以及加入了注解作为查询条件。这个接口是BeanFactory一个很好的补充,由于有的容器可能不需要具备批量操作功能和注解的作用,所以将这部分功能放在了ListableBeanFactory当中,而不是BeanFactory当中,这样解耦也会非常好。
5.HierarchicalBeanFactory——分层的BeanFactory
//得到父容器
BeanFactory getParentBeanFactory();
//判断当前容器是否包含相应的Bean实例,不包含父类容器的
boolean containsLocalBean(String name);
该接口的出现使容器具备了继承的作用:子容器可以得到父容器的实例从而拿到父容器持有的的bean实例,同时子容器也可以单独判断当前容器是否包含bean实例。
6.ApplicationContext——具备完整功能的接口,应用上下文
//应用的ID,唯一标识
String getId();
//应用的名称
String getApplicationName();
//应用的展示名称
String getDisplayName();
//应用的启动时间
long getStartupDate();
//得到父应用
ApplicationContext getParent();
//暴露AutowireCapableBeanFactory
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
概述:ApplicationContext接口定义了应用的一些行为,实现这个接口的类则表示属于一个完整的应用。该接口实现了BeanFactory类族以及ResourceLoader类族,还有EnvironmentCapable、ApplicationEventPublisher、MessageSource等接口,具备IOC的储存功能和资源的加载功能,以及剩下的几个接口的功能(后文会分析这几个接口的作用)。
接口的作用:ApplicationContext的作用更像是一个整合,赋予了应用的一些个性标识,不过也定义了父子应用的概念。AutowireCapableBeanFactory 接口的作用也是后文分析。
这个接口的重大意义在于,从单一的IOC容器转变成了应用容器,还具备资源加载功能。
7.ConfigurableApplicationContext——可配置的应用上下文
//上下文路径的分隔符,意思是一个字符串如果是上下文路径,且包含以下符号,那么就是多个上下文路径,
//中间被以下分隔符隔开。
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
//ConversionService的默认名称
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
//LoadTimeWeaver的默认名称
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
//Environment的默认名称
String ENVIRONMENT_BEAN_NAME = "environment";
//java.lang.System的getProperties()方法的默认名称
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
//java.lang.System的getenv()方法的默认名称
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
//给应用上下文设置唯一ID
void setId(String id);
//给应用上下文设置父应用上下文
void setParent(ApplicationContext parent);
//给应用上下文设置ConfigurableEnvironment
void setEnvironment(ConfigurableEnvironment environment);
//得到Environment,返回值类型是ConfigurableEnvironment,重写是因为父接口返回的是Environment
@Override
ConfigurableEnvironment getEnvironment();
//给应用上下文添加后置处理器
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
//给应用上下文添加应用监听器
void addApplicationListener(ApplicationListener<?> listener);
//给应用上下文添加协议解析器
void addProtocolResolver(ProtocolResolver resolver);
//刷新应用上下文
void refresh() throws BeansException, IllegalStateException;
//注册钩子,应用上下文关闭的时候会调用
void registerShutdownHook();
//关闭应用上下文,重写了父接口Closeable的close()方法,因为父接口的close()抛的是IO异常,属于关
//闭流的作用,而这里只是关闭应用上下文
@Override
void close();
//判断当前应用上下文是否为激活状态
boolean isActive();
//得到ConfigurableListableBeanFactory这个IOC容器(这个接口后文分析)
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
该接口是ApplicationContext的补充,ApplicationContext定义了一个应用应该有哪些东西,但是没有定义这些东西从哪里来,也就是说ApplicationContext无法改变其中的状态,所以实现ConfigurableApplicationContext接口的类除了能够改变应用上下文的状态,还能够管理其生命周期(实现了Lifecycle接口)。
8.AbstractApplicationContext——抽象的应用上下文,给出了部分具体实现,部分方法仍然保留为抽象方法(未完待续)