摘自: https://javadoop.com/post/spring-ioc
IOC 最重要的两处
一个是创建bean容器
一个是初始化bean
启动spring容器的例子:
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml");
}
以上代码就可以利用配置文件来启动一个Spring容器了,使用maven直接在dependencies中加入以下依赖即可,个人比较反对那些不知道要添加什么依赖,然后把Spring的所有相关依赖都加进去的方式。
org.springframework spring-context 4.3.11.RELEASEspring-context 会自动将spring-core、spring-beans、spring-aop、spring-expression 这几个基础jar包带进来。
在ClassPath中寻找xml配置文件,根据xml文件内容来构建ApplicationContext.
ApplicationContext (应用上下文)
↑
ConfigurableApplicationContext (可配置应用上下文)
↑
AbstractApplicationContext (抽象应用上下文)
↑ ↑
AbstractRefreshableApplicationContext GenericApplicationContext
(抽象可翻新应用上下文) (未注册应用上下文)
↑ ↑
abstractXmlApplicationContext AnnotationConfigApplicationContext
(抽象可扩展应用上下文) (注解配置应用上下文)
↑ ↑
ClassPathXmlApplicationContext FileSystemXmlApplicationContext
(类路径可扩展应用上下文) (文件系统可扩展应用上下文)
(题外话:(其实就是我想到的一些废话,可略过)ClassPathXmlApplicationContext和FileSystemXmlApplicationContext继承的类都是abstaract(抽象)修饰的,而继承abstract类的子类必须实现abstract类中的所有抽象方法,否则子类也必须用abstract修饰,由此推断以上两个类中拥有它们所继承 的abstract类中的所有抽象方法)
FileSystemXmlApplicationContext的构造函数需要一个xml配置文件在系统中的路径,其他和ClassPathXmlApplicationContxt基本一样。
AnnotationConfigApplicationContext :是基于注解使用的,它不需要配置文件,采用Java配置类和各种注解来配置,是比较简单的方式,大势所趋。
BeanFactory :生产bean的工厂,负责生产和管理各个bean实例。(ApplicationContext其实就是一个BeanFactory)
ApplicationContext : 继承和ListableBeanFactory,这个Listable的意思就是,通过这个接口,我们可以获取多个Bean,最顶层的BeanFactory接口的方法都是获取单个Bean的。
ApplicationContext : 继承了HierarchicalBeanFactory,Hierarchical(分层),也就是说我们在应用中可以起多个bean,然后可以将各个BeanFactory设施为父子关系
AutowireCapableBeanFactory Autowire(自动装配) :这个是用来自动装配Bean用的,但是ApplicationContext并没有继承它。但是使用了组合,ApplicationContext接口定义中的最后一个方法getAutowireCapableBeanFactory()。
ConfigurableListableBeanFactory :也是一个特殊的接口,它继承了ListbleBeanFactory、hierarchicalBeanFactory、AutowireCapableBeanFactory,而ApplicationContext没有。
启动过程分析
ClassPathXmlApplicationContext的构造方法:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext{
private Resource[] configresources;09
//如果已经有ApplicationContext并需要配置成父子关系,那么调用这个构造方法
public ClassPathXmlApplicationContext(ApplicationContext parent){
super(parent);
}
...
public ClassPathXmlApplicationContext(String[] configLocations,boolean refresh,ApplicationContext parent) throws BeansException{
super(parent);
//根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);
if(refresh){
refresh();//核心方法
}
}
...
}
这里为什么是refersh(),而不是init()这种名字的方法。因为ApplicationContext建立起来以后,其实我们是可以通过调用refresh()这个方法重建的,refresh()会将原有的ApplicationContext销毁,然后再重新建立一次初始化操作。
refresh()方法调用了很多方法:
public void refresh()throws BeansException,IllegalStateException{
//加锁,防止refresh()还没结束,又来一个启动或销毁容器的操作
synchronized(this.startupShutdownMonitor){
//准备工作,记录下容器的启动时间、标记‘已启动’状态、处理配置文件中的占位符
prepareRefersh();
//这一步比较关键,这步完成后,配置文件就会解析成一个个Bean定义,注册到BeanFactory中,
//这里的Bean还没有初始化,只是配置信息提取出来了,
//注册也只是将这个信息都保存到了注册中心
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//设置BeanFactory的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的bean
prepareBeanFactory(beanFactory);
try{
//这里需要知道BeanFactoryPostProcessor 这个知识点,Bean如果实现了此接口,
//那么在容器初始化以后,Spring会负责调用里面的postProcessBeanFactory方法
//这里提供给子类的扩展点,到这里的时候,所有的Bean都加载、注册完成了,但是都没
//有初始化具体的子类可以在这步的时候添加一些特殊的BeanFactoryPostProcessor的
//实现类或做其他操作
postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory)方法
invokeBeanFactoryPostProcessors(beanFactroy);
//注册BeanPostProsscessor的实现类,注意看和BeanFactoryPostProcessor的区别
//此接口两个方法:postProssorBeforeInitialization和postProcessorAfterInitialization
//两个方法分别在Bean初始化之前和初始化之后得到的执行,注意到这里Bean还没初始化
registerBeanPostProcessor(beanFactory);
//初始化当前ApplicationContext的MessageSource
initMessageSource();
//初始化当前ApplicationContext的事件广扩展
initApplicationEventMulticaster();
//模块方法,具体的子类可以在这里初始化一些特殊的Bean(在初始化singleton beans之前)
onRefresh();
//注册事件监听器,监听器需要实现ApplicationListener 接口。
registerListeners();
//重点
//初始化所有的singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
//最后,广播事件,ApplicationContext 初始化完成
finishRefresh();
}catch(BeansException ex){
if(logger.isWarnEnabled()){
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
//销毁已经初始化的singleton的 Beans,以免有些bean会一只占用资源
destroyBeans();
//重置active
cancelRefresh(ex);
//外抛异常
throw ex;
}finally{
//重置Spring核心的普通内省缓存,因为我们可能再也不需要单例bean的元数据了
resetCommonCaches();
}
}
}
下面,开始来分解一下refresh()方法、
创建Bean容器前的准备工作
protected void prepareRefresh(){
//记录启动时间
//将active属性设置为true,closed 属性设置为false,特们都是AtomicBoolean类型
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if(logger.isInfoEnabled){
logger.info("Refreshing" + this);
}
//在上下文环境中初始化任何占位符属性源
initPropertySources();
//校验xml配置文件
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
创建Bean容器,加载并注册Bean
--------持续更新中
狗剩er 发布了10 篇原创文章 · 获赞 0 · 访问量 76 私信 关注