Spring 使用Xml注入bean全过程

首先创建一个Springdemo项目

结构如下:
Spring 使用Xml注入bean全过程_第1张图片
编写一个接口IAnimal

package com.example.spring.springdemo.animal;

public interface IAnimal {
    /**
     * 动物叫唤
     * @return
     */
    String call();
}

两个实现类Cat,Dog除了名字,内部实现都一样。

package com.example.spring.springdemo.animal.animalImpl;

import com.example.spring.springdemo.animal.IAnimal;

/**
 * @program my_study_test
 * @author: jan
 * @create: 2020/11/28 20:25
 */
public class Cat implements IAnimal {
    private String call;

    public Cat(String call) {
        this.call = call;
    }

    public String call() {
        return call;
    }
}

主类SpringDemoApplication

package com.example.spring.springdemo;

import com.example.spring.springdemo.animal.IAnimal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDemoApplication {
    public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        IAnimal cat = (IAnimal) context.getBean("cat");
        System.out.println(cat.call());
    }

}

在resources中创建application.xml文件,spring将会加载这个xml为我们创建两个bean,id唯一,将会用来获取bean实例,这里使用构造方法传入call的值。


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dog" class="com.example.spring.springdemo.animal.animalImpl.Dog">
        <constructor-arg name="call" value="wang!!!"/>
    bean>
    <bean id="cat" class="com.example.spring.springdemo.animal.animalImpl.Dog">
        <constructor-arg name="call" value="miao!!!"/>
    bean>

beans>

启动流程:

		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

这里使用ClassPathXmlApplicationContext创建一个context对象,在ClassPathXmlApplicationContext的构造方法中:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);//未指定parent
		setConfigLocations(configLocations);//存放我们将要解析的xml文件名
		if (refresh) {
			refresh();//主要工作在这里做的
		}
	}

refresh()做了主要的工作,直接跳到了AbstractApplicationContext类,多层继承shift+option+command+u查看继承实现关系图:
Spring 使用Xml注入bean全过程_第2张图片
看看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.
			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();
			}
		}
	}

里面的内容太多,主要看两个方法:
obtainFreshBeanFactory();
finishBeanFactoryInitialization(beanFactory);

单拿出来看obtainFreshBeanFactory()获取新的工厂实例,这一步涵盖了非常多的内容,其中就包括我们xml的解析以及bean的构建保存。

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

进入方法内部这里又调用了AbstractApplicationContext类refreshBeanFactory();方法。

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();//子类实现
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

进入子类AbstractRefreshableApplicationContext中,方法内部:

	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();//DefaultListableBeanFactory beanFactory 将会存放Spring 创建的Bean描述对象
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);//主要看这里
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

loadBeanDefinitions(beanFactory);AbstractXmlApplicationContext中,做了非常多的事情,重载了很多种,太长了就不全部截取了。

XmlBeanDefinitionReader类loadBeanDefinitions方法调用doLoadBeanDefinitions方法
其中做了两件事:

  1. Document doc = doLoadDocument(inputSource, resource);通过JAXP解析xml文件,将其转换成Document对象,
  2. return registerBeanDefinitions(doc, resource);便是将解析的xml转化成BeanDefinition对象保存。


令人所迷惑的xml到对象的转变就是发生在这里,不过值得注意的是,这里的转换只是生成了对象的描述BeanDefinition,也就说该怎么创建它,实际的生成在后面。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}
		....

回到refresh()方法,前面经过了obtainFreshBeanFactory()方法,获取了工厂实例,里面已经有了spring要为我们创建bean的id以及描述BeanDefinition。

真正创建xml bean的方法是 finishBeanFactoryInitialization(beanFactory); ,实际调用了DefaultListableBeanFactorypreInstantiateSingletons();

前面obtainFreshBeanFactory()解析后的BeanDefinition存放在这里

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		...
		beanFactory.preInstantiateSingletons();
	}


DefaultListableBeanFactorypreInstantiateSingletons()方法调用了AbstractBeanFactory类getBean(beanName);

	public void preInstantiateSingletons() throws BeansException {
		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			...
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}
		...

直接调了AbstractBeanFactorydoGetBean()方法,调用DefaultSingletonBeanRegistry中的getSingleton().

不过会先调用AbstractAutowireCapableBeanFactorycreateBean(beanName, mbd, args);方法,在方法中进行了实例化 Instantiation、属性赋值 Populate、初始化 Initialization。

					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {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;
							}
						}
					});

DefaultSingletonBeanRegistry调用addSingleton(beanName, singletonObject);
这里便是bean实例保存的最后一步了,bean将会被保存在 singletonObjectsConcurrentHashMap 中。

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

到此,bean从xml描述到实例化就结束了,当我们使用IAnimal cat = (IAnimal) context.getBean("cat");会通过AbstractBeanFactory到达DefaultSingletonBeanRegistry获取之前存在singletonObjects中的实例。

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		...

虽然极力想描述清楚,但是里面涉及的细节太多,简单的说可以是如下流程:obtainFreshBeanFactory()解析xml,finishBeanFactoryInitialization(beanFactory); 完成注入。
Spring 使用Xml注入bean全过程_第3张图片

全文是依据打断点截取关键部分阐述,省略许多if判断描述。

以上内容虽然没有多少养分,但是,从中能了解到Spring的一些思想:
IoC:控制翻转,控制权从应用程序转意到框架,Spring帮我们处理这些资源(解析xml,创建实例等)
DI:依赖注入
特点
不需要手动去new,有IoC容器帮我们创建,被动实例化。
不需要主动装配对象直接的依赖关系,而是描述需要什么,IoC容器会帮你装配。
最少知识原则,不依赖具体实现,只知道需要提供某类服务的对象,松散耦合,一个对象应当对其他对象尽可能少的了解。

关于bean的生命周期

这一块内容错综复杂,穿插在上文的整个启动流程中,简单说来就是获取BeanDefinition,然后进行

实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction


其中对应到上面的具体代码是在AbstractAutowireCapableBeanFactory类doCreateBean方法中

createBeanInstance() -> 实例化
populateBean() -> 属性赋值
initializeBean() -> 初始化

具体代码位置如下,怎么来到这里还得回看refresh()中的finishBeanFactoryInitialization()方法中,忘记了点这里[一键传送]

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);//这里,实例化
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
		mbd.resolvedTargetType = beanType;

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);//这里,属性填充
			if (exposedObject != null) {
				exposedObject = initializeBean(beanName, exposedObject, mbd);//这里,初始化
			}
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()

此外,这其中还穿插了BeanPostProcessor以及子类InstantiationAwareBeanPostProcessor等类的如postProcessBeforeInstantiationpostProcessAfterInstantiation各种后处理器拓展点切入。这里面涉及就比较细节了,详细的话有4个后处理器,可以参考一下博客:

  1. Spring 中的 BeanPostProcessor接口
  2. 请别再问Spring Bean的生命周期了!
  3. Spring中bean的生命周期(最详细)

关于Aware,Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。

在前面AbstractAutowireCapableBeanFactorydoCreateBean方法中进行实例化,属性赋值,初始化,在初始化方法initializeBean中调用了invokeAwareMethods(beanName, bean);判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。

private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

关于依赖注入:
A 创建过程中需要 B,于是 A 将自己放到(addSingletonFactory()方法)三级缓(DefaultSingletonBeanRegistry类)里面 ,去实例化 B
B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了!
然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
B 顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
然后回来接着创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面。
1.Spring 如何解决循环依赖的问题?
2.spring是如何解决循环依赖的?
3.明明一级缓存就够用,为什么要使用多级缓存?

你可能感兴趣的:(学习,spring)