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

spring源码分析-01-IOC初始化容器过程分析

2019-01-02 14:10 453 查看

入口:

public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
throws BeansException {

super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh();
}

主要方法就是refresh方法进行IOC容器初始化。初始化过程包括:

  • 定位
  • 加载:加载过程最复杂,先将xml读取为Element然后在将Element转换为BeanDefinitions。里面还有好多逻辑
  • 注册:注册比较简单,加载完毕后生成BeanDefinitionHolder对象,这个对象持有beanName和BeanDef所以直接get到然后放到Map结构中

最后将xml解析为BeanDefinition对象,放到map中,当调用getBean()执行时就会

  • 实例化
  • 依赖注入
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//调用容器准备刷新方法,获取容器的当前时间,同时给容器设置同步标识
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
//告诉子类启动refreshBeanFactory方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动
/**
* 1.AbstractRefreshableApplicationContext.refreshBeanFactory这个方法里面就是构造BeanFactory
* 2.然后调用AbstractRefreshableApplicationContext.getBeanFactory赋值给ConfigurableListableBeanFactory
* 3.返回return这个BeanFactory
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
//为BeanFactory配置容器特性,例如类加载器,事件处理器等
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
//国际化初始化
initMessageSource();

// Initialize event multicaster for this context.
//事件传播
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

上面refresh方法实现的代码

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这个就是创建IOC容器的方法。所以继续看这个方法的代码

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//采用委派模式,父类提供接口,子类提供实现
//创建BeanFactory的方法。
refreshBeanFactory();

//创建好BeanFactory之后,通过getBeanFactory获得方法
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

调用父类

AbstractRefreshableApplicationContext.refreshBeanFactory()
创建容器。然后调用父类
AbstractRefreshableApplicationContext.getBeanFactory()
获得创建的IOC容器,并将这个IOC容器返回出去。下面是refreshBeanFactory代码第一部分是判断容器是否存在如果存在则销毁容器,重新创建。

protected final void refreshBeanFactory() throws BeansException {
//判断是否已经存在IOC容器,如果存在,则销毁
/**
* hasBeanFactory()在判断AbstractRefreshableApplicationContext里面的成员变量beanFactory如果不是空,则需要销毁IOC容器
*/
if (hasBeanFactory()) {
//主要就是清除map。IOC的容器就是一个Map
destroyBeans();
//将BeanFactory=null
closeBeanFactory();
}
try {
//创建IOC容器,这个时候的beanFacotr仅仅只是new一下,容器里面还没有东西
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等等
customizeBeanFactory(beanFactory);

//调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions,具体的实现调用子类容器
//使用子类AbstractXmlApplicationContext来实现
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

从上面的代码可以知道spring实例了一个DefaultListableBeanFactory给用户使用。在

DefaultListableBeanFactory beanFactory = createBeanFactory();
里面只是new了一个容器,当时容器里面什么都没有真正填充容器的是loadBeanDefinitions(beanFactory)。

//调用AbstractXmlApplicationContext.loadBeanDefinitions这里采用了委派模式,自己不做事,交给子类做事
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//创建XmlBeanDefinitionReader,即Bean的读取器,并通过回调设置到容器beanFactory里面(目前beanFactory仅仅只是new了一个对象)容器使用这个读取器去读取Bean定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
//为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的父类AbstractApplicationContext 继承了 DefaultResourceLoader,因此容器也是一个Bean读取器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);

//为Bean读取器设置SAX xml解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//当Bean读取器读取Bean定义的xml资源文件时,启用xml校验机制,此处仅仅是设置了校验标志位:设置true
initBeanDefinitionReader(beanDefinitionReader);

//Bean读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}

下面关于loadBeanDefinitions的层次很深,需要认真跟踪。

//AbstractXmlApplicationContext.loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取Bean定义资源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//xml Bean读取器调用父类AbstractBeanDefinitionReader读取定位的Bean定义资源
reader.loadBeanDefinitions(configResources);
}
//采用委派模式,调用子类的获取Bean定义资源定位的方法,该方法在ClassPathXmlApplicationContext中实现
//如果子类种获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

上面将资源定位到,调用XML读取器解析xml。调用

XmlBeanDefinitionReader.loadBeanDefinitions()
继续解析xml在spring里面如果某个方法以do开头那么这个方法就是真正做事的方法,其他方法都是套路,不停的调用调用而已看到下面方法

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<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//真正做事的人找到了!
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();
}
}
}

继续跟踪doLoadBeanDefinitions。这个方法里面首先将xml文件流解析为Document对象。

Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);

继续进入

registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建DefaultBeanDefinitionDocumentReader对象,这个对象里面存放就是bean alias import resource等等
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();

//前面已经将XML文件内容转换为Document对象。
//下面方法是将Document对象转成Spring里面的BeanDefinition对象
//DefaultBeanDefinitionDocumentReader类里面的方法
//并且将BeanDefinition注册到IOC容器中
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

return getRegistry().getBeanDefinitionCount() - countBefore;
}

上面

registerBeanDefinitions
中主要就是
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
将Document对象转成BeanDefinitions对象。继续进入这个方法。找到
DefaultBeanDefinitionDocumentReader.registerBeanDefinitions
方法。(马上就可以看到曙光了)

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//从Document里面获得Element的根元素开始解析。
//以do开头的方法就是具体做事的方法
doRegisterBeanDefinitions(root);
}

继续看doRegisterBeanDefinitions方法

protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//创建BeanDefinitionParserDelegate对象。这个对象就是解析Document对象中的数据。是要生成BeanDefinition的处理对象。在下面创建对象的时候已经将配置文件中<beans>里面的默认熟悉解析出来了
/**
* 在<beans><beans/>里面主要定义了默认的属性如下
default-lazy-init
default-merge
default-autowire
default-dependency-check
default-autowire-candidates
default-init-method
default-destroy-method
*/
this.delegate = createDelegate(getReaderContext(), root, parent);

//默认的命名空间,也就是
/**
*xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
*/
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;
}

上面的方法首先创建

BeanDefinitionParserDelegate
,然后读取配置文件中配置的全局默认属性。紧接着处 1bb8c 理命名空间。然后处理
preProcessXml(root);
这个方法是空的。真正处理配置的方法是
parseBeanDefinitions(root, this.delegate);

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
//取出root下面的子节点。一个一个的bean
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;

//判断当前节点是否是命名空间,如果是命名空间则交给命名空间类处理
if (delegate.isDefaultNamespace(ele)) {
//普通类型,则开始将Element转换成BeanDefinitions。下面的方法也区分是什么类型:import;alias;bean;beans
//一般的spring配置文件根目录只包含上面四种情况,所以下面的方法分别处理
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

上面方法中从node节点中取出所有子节点,如果是普通的类型则开始解析

parseDefaultElement(ele, delegate);

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//处理import
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//处理alias。在SimpleAliasRegistry对象中有一个map结构,将name和alias保存到map里面
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//处理bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//处理beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
//递归调用
doRegisterBeanDefinitions(ele);
}
}

看到上面的方法心里终于放下心了,已经找到调用真正真正处理的地方了。直接进入处理Bean的地方

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将Element转成BeanDefinition。然后将BeanDefinition和BeanName交给BeanDefinitionHolder持有
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//将BeanDefinition注册到IOC容器中
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));
}
}

上面代码中

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
就是处理Element的方法,将Element转化成BeanDefinitionsHolder这个对象里面持有beanName和BeanDefinitions。然后就是注册过程。注册过程简单,调用
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
内部就是将beanName和BeanDefinitions关联起来

public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
//注册,将beanName和BeanDefinitions放到map中。使用的类:DefaultListableBeanFactory
//主要有一下数据:
// beanDefinitionMap:beanName作为key,BeanDefinitions作为value
//List<String> beanDefinitionNames:list保存beanName
//private volatile Set<String> manualSingletonNames保存单例的名字
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

上面已经将xml文件注册成了BeanDefinitions对象并用键值对的方式保存到Map中。下面就是依赖注入的过程。当调用getBean()方法时就会触发依赖注入。在spring源码中经常看到N多个重载方法,一般都是有一个最全参数的重载方法,然后其他方法都是有默认值的调用这个最全参数的方法。在getBean中同样是这样设计的。可以找到getBean的入口方法:

AbstractApplicationContext.getBean(String name)
所有的重载方法getBean最后都是doGetBean()。代码如下
AbstractBeanFactory.doGetBean

protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//1.如果是FactoryBean这种Bean都是以&开头。所以需要去掉&
//2.如果name的别名,则需要在SimpleAliasRegistry里面进行判断获取的真正的那么
final String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
//从缓存中获取对象,避免重复创建
Object sharedInstance = getSingleton(beanName);
System.out.println(sharedInstance);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/*这里 的 getObjectForBeanInstance 完成 的 是 FactoryBean 的 相关 处理,
以 取得 FactoryBean 的 生产 结果, BeanFactory 和 FactoryBean 的 区别 已经 在前面 讲过, 这个 过程 在后面 还会 详细 地 分析*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
/*
这里 对 IoC 容器 中的 BeanDefintion 是否 存在 进行检查,
检查 是否 能在 当前 的 BeanFactory 中 取得 需要 的 Bean。
如果 在 当前 的 工厂 中 取 不到, 则 到 双亲 BeanFactory 中 去取;
如果 当前 的 双亲 工厂 取 不到, 那就 顺着 双亲 BeanFactory 链 一直 向上 查找*/
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

try {
//通过beanName获得BeanDefinition对象  //这里 根据 Bean 的 名字 取得 BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
//检查bean配置是否设置了depend-on属性。即实例A需要先实例B
//获取 当前 Bean 的 所有 依赖 Bean, 这样 会 触发 getBean 的 递归 调用, 直到 取 到 一个 没有
// 任何 依赖 的 Bean 为止
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/*这里 通过 调用 createBean 方法 创建 Singleton bean 的 实例, 这里 有一个 回 调 函数 getObject, 会在 getSingleton 中 调用 ObjectFactory 的 createBean*/

// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

// Check if required type matches the type of the actual bean instance.
// 这里 对 创建 的 Bean 进行 类型 检查, 如果 没有 问题, 就 返回 这个 新 创建 的 Bean, 这个 Bean 已经 //是 包含 了 依赖 关系 的 Bean
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: