应用上下文
代码地址:WangChao-ly/chao-spring at application-context (github.com)
建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!
应用上下文ApplicationContext是spring中较之于BeanFactory更为先进的IOC容器,ApplicationContext除了拥有BeanFactory的所有功能外,还支持特殊类型bean如上一节中的BeanFactoryPostProcessor和BeanPostProcessor的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。
BeanFactory是spring的基础设施,面向spring本身;而ApplicationContext面向spring的使用者,应用场合使用ApplicationContext。
具体实现查看AbstractApplicationContext#refresh方法即可。注意BeanFactoryPostProcessor和BeanPostProcessor的自动识别,这样就可以在xml文件中配置二者而不需要像上一节一样手动添加到容器中了。
结构说明:
ApplicationContext
- 接口层
- 顶层接口ApplicationContext继承了ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader等接口,该类拥有了资源加载和BeanFactory的功能。
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader {
}
- ConfigurableApplicationContext:该接口继承了ApplicationContext,并提供了refresh()方法,在方法在xml读取后调用,用来初始化容器,做为容器的入口。
public interface ConfigurableApplicationContext extends ApplicationContext{
/**
* 刷新容器
* @throws BeansException
*/
void refresh() throws BeansException;
}
- 实现类
- AbstractApplicationContext:抽象应用上下文,该类的功能主要是提供BeanFactoryPostProcessor注册BeanPostProcessor的处理方案,并且对外提供一些获取Bean的方法(原则上是调用beanFactory的相关方法),同时提供了抽象方法用来加载资源和具体的BeanFactory初始化等操作用子类来实现。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException {
//创建BeanFactory,并加载BeanDefinition
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
beanFactory.preInstantiateSingletons();
}
/**
* 创建BeanFactory,并加载BeanDefinition,子类会调用之前写好的类来加载资源和实现注入
* @throws BeansException
*/
protected abstract void refreshBeanFactory() throws BeansException;
/**
* 从容器中获取BeanFactoryPostProcessor,实例化bean之前调用方法
* @param beanFactory
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){
Map<String, BeanFactoryPostProcessor> beanOfType = beanFactory.getBeanOfType(BeanFactoryPostProcessor.class);
for(BeanFactoryPostProcessor beanFactoryPostProcessor:beanOfType.values()){
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
/**
* 注册BeanPostProcessor
* @param beanFactory
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeanOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name,requiredType);
}
@Override
public <T> Map<String, T> getBeanOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeanOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
/**
* 获取BeanFactory,返回为接口
* @return
*/
public abstract ConfigurableListableBeanFactory getBeanFactory();
}
- AbstractRefreshableApplicationContext:该类提供具体的创建BeanFactory方法,和抽象的加载BeanDefinition的方法(这个由子类来实现)。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{
private DefaultListableBeanFactory beanFactory;
@Override
protected final void refreshBeanFactory() throws BeansException{
//和该业务无关的抽象出一个方法
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
protected DefaultListableBeanFactory createBeanFactory(){
return new DefaultListableBeanFactory();
}
/**
* 加载BeanDefinition
* @param beanFactory
* @throws BeansException
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException;
@Override
public DefaultListableBeanFactory getBeanFactory(){
return beanFactory;
}
}
- AbstractXmlApplicationContext:该类继承于AbstractRefreshableApplicationContext,实现了资源加载的具体解决方案,引入了XmlBeanDefinitionReader,该类是之前讲过的用来读取xml文件,并且加载到容器中的类,同时提供抽象方法getConfigurations,这个也由子类来实现。
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory,this);
String[] configurations = getConfigurations();
if(configurations!=null){
beanDefinitionReader.loadBeanDefinition(configurations);
}
}
/**
* 获取配置路径
* @return
*/
protected abstract String[] getConfigurations();
}
- ClassPathXmlApplicationContext:该类是对外使用的类,只需要用户传入xml文件地址即可,程序会配置configurations并且调用refresh方案,从而容器就能正常走通了。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext{
private String[] configurations;
public ClassPathXmlApplicationContext(String configuration) throws BeansException{
this(new String[]{configuration});
}
public ClassPathXmlApplicationContext(String[] configurations) throws BeansException{
this.configurations = configurations;
refresh();
}
@Override
protected String[] getConfigurations() {
return this.configurations;
}
}
总结: 从源码书写方案学习下来,感觉非常优美,接口负责将方法进行规范且对外引用。类之间功能层次分明,层层调用,如果是需要方法可以先调用抽象方法,然后具体的实现让子类来实现,对外最终继承所有功能于ClassPathXmlApplicationContext这个类。
感悟:这里可以用一个化妆来比喻
开始一个人,它没有任何装饰,一个通用标准指示他要去戴帽子(实现了通用接口),这时候他写一个戴帽子的抽象方法,让帽子间类去继承这个人,然后实现戴帽子方法,这样人就戴好了帽子,对外只要调用帽子这个类就行。