spring 源码解读(摘抄)

摘自: 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.RELEASE
spring-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

--------持续更新中

spring 源码解读(摘抄)spring 源码解读(摘抄) 狗剩er 发布了10 篇原创文章 · 获赞 0 · 访问量 76 私信 关注
上一篇:Oauth2.0(三):Access Token 与 Refresh Token


下一篇:mobile-pull-to-refresh: 移动端下拉刷新控件