您的位置:首页 > 编程语言 > Java开发

spring IOC源码分析(一)bean工厂的创建加载过程

2019-05-31 19:54 639 查看

最近学的比较散乱,没有真正学到比较重要的东西。这几天把sprign源码再看一遍,整理下以前看的经历,同时把相关的个人心得记录下来。
spring两大功能模块,IOC和AOP,在之前已经知到了IOC原理是反射来获取bean实例,而AOP是动态代理来实现的。这里先介绍下IOC的源码,它是如何来实现的。当然目前能学到的也只是比较浅的大概流程,再复杂点的看起来就比较吃力了。
推荐在学习spring源码的时候下载一份来,好方便注释。这里先从在一开始学习时见到的说起:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);
进入ClassPathXmlApplicationContext的构造器,在顺着构造器分析来到这,查看注释:

// 使用给定的父级创建新的ClassPathXmlApplicationContext,
// 从给定的XML文件加载定义。
//加载所有bean定义并创建所有单例
//或者,在进一步配置上下文后手动调用refresh。
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

从代码可以看出这里有两个方法setConfigLocations(configLocations)和重点refresh()。显然前者是进行配置的,打开看到:

public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
//里面对locations进行了空值判定,如果有一个地址是空的,会抛出异常
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//进一步解析地址
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}

于是spring相关的配置缓存在configLocations中,回到核心方法refresh()中,追踪打开:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//在刷新前的准备,设置启动日期和标志以及属性源初始化
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
//获取更新后的子类工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
//配置bean工厂以便在此上下文中使用。
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
//允许在上下文的子类中对bean factory进行后处理
//注册request/session scopes,一个ServletContextAwareProcessor处理器等。
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
//在上下文中调用注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
//注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
//为此上下文初始化消息源。
initMessageSource();

// Initialize event multicaster for this context.
//为此上下文初始化事件多主机。
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
//初始化特定上下文子类中的其他特殊bean。
onRefresh();

// Check for listener beans and register them.
//检查侦听器bean并注册它们。
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
//实例化所有剩余的(非lazy init)单例。
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
//最后一步:发布对应的事件。
finishRefresh();
}

在prepareRefresh()中打开可以发现这里获取了当前时间,以及进行一些设置,为接下来的刷新获取容器作准备;
然后是重点的obtainFreshBeanFactory(),获取bean工厂。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//刷新获取DefaultListableBeanFactory类型的bean工厂,实质的配置也是在这里面配置的
ConfigurableListableBeanFactory beanFactory = getBeanFactory();//获取配置好的DefaultListableBeanFactory
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

首先点开refreshBeanFactory(),它的实现类是AbstractRefreshableApplicationContext

protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();//在DisposableBean接口中,destory(),主要的销毁办法还是通过Map或set的clear()来销毁的
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//创建工厂是默认的DefaultListableBeanFactory类型
beanFactory.setSerializationId(getId());//设立一个id
customizeBeanFactory(beanFactory);//对上面创建的工厂进行初始化,设置是否可以被子类重写等
loadBeanDefinitions(beanFactory);//加载bean定义,用于读取xml配置文件
//在解析<Bean>元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,
// 将<Bean>元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

首先是需要销毁之前的bean和beanFactory,对于bean实例的销毁主要是通过之前保存的map,clear()来清除。然后来到createBeanFactory(),这里创建beanFactory,是DefaultListableBeanFactory类型的,点开createBeanFactory(),发现里面是使用DefaultListableBeanFactory的构造器参数是getInternalParentBeanFactory()

protected DefaultListableBeanFactory createBeanFactory() {
////创建并返回一个DefaultListableBeanFactory工厂,其中参数是他的父工厂
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

追踪getInternalParentBeanFactory()发现返回ApplicationContext,ApplicationContext是由BeanFactory派生而来的。得到ApplicationContext后便缓存在AbstractBeanFactory抽象类中,同时返回到refreshBeanFactory()中。然后看到loadBeanDefinitions(beanFactory),追踪来到它的实现类AbstractXmlApplicationContext,

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//方法内部是采用XmlBeanDefinitionReader来读取加载bean对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
//使用此上下文的资源加载环境
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//允许子类提供读卡器的自定义初始化,
// 然后继续实际加载bean定义。
initBeanDefinitionReader(beanDefinitionReader);
//重点
loadBeanDefinitions(beanDefinitionReader);//通过XMLBeanDefinitionReader结合location路径信息读取Resources资源信息
}

我们发现,这里对刚才获得的DefaultListableBeanFactory进行了xml的加载并初始化。这里进行了一些简单的配置后来到主要的加载xml的方法 loadBeanDefinitions(beanDefinitionReader),追踪源码后来到:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource);
}

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获得一个io 其实resource对象就是Spring容器中我们配置的xml文件
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//开始准备解析xml文件了
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//重点doLoadBeanDefinitions
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

这里才是真正开始加载xml配置的地方,具体的解析方 26a77 法实在doLoadBeanDefinitions里面。由于我们直接获取到的并不是实例bean而是BeanDefinitions ,所以当我们追踪doLoadBeanDefinitions到doRegisterBeanDefinitions方法的时候就差不多能找到它是如何解析这些xml的标签元素的

protected void doRegisterBeanDefinitions(Element root)
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//空方法
preProcessXml(root);
//重点方法
parseBeanDefinitions(root, this.delegate);
//空方法
postProcessXml(root);

this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//如果使用了Spring默认的XML命名空间
if (delegate.isDefaultNamespace(root)) {
//遍历根元素的所有子节点
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//如果该节点是XML元素节点
if (node instanceof Element) {
Element ele = (Element) node;
//如果该节点使用的是Spring默认的XML命名空间
if (delegate.isDefaultNamespace(ele)) {
//使用Spring的Bean规则解析元素节点
//重点
parseDefaultElement(ele, delegate);
}
else {
//没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点
//(如:自定义的xsd等)
delegate.parseCustomElement(ele);
}
}
}
}
else {
//Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析Document根节点
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//如果元素节点是<Import>导入元素,进行导入解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//如果元素节点是<Alias>别名元素,进行别名解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//如果普通的<Bean>元素,按照Spring的Bean规则解析元素
//bean定义解析入口
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

这里是对不同的元素进行解析,由于我们的目标是bean,于是进入processBeanDefinition

/**
* 处理给定的bean元素,分析bean定义
* 并在注册处注册。
* 解析bean资源
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//BeanDefinitionHolder是对BeanDefinition的封装,包括BeanDefinition,beanName,aliases
//对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
//next
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//向Spring IoC容器注册解析得到的Bean定义,
//这是Bean定义向IoC容器注册的入口 ,实际上是放到一个Map里面
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

在解析过后,BeanDefinition便注册进去了。回到obtainFreshBeanFactory()还有一点要说明的是,由于DefaultListableBeanFactory是ConfigurableListableBeanFactory的实现类,所以getBeanFactory()返回的是AbstractRefreshableApplicationContext中DefaultListableBeanFactory类型的数据。
这下bean工厂基本上是获取到了,再经过一些后续处理后就可以用来获取bean了。

也许有些地方表述的不够好或者错了,还多体谅。下一节将整理关于getBean的流程分析。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: