Spring IOC设计了两个接口BeanFactory实现了容器最基本的功能,ApplicationContext应用上下文在BeanFactory的基础上增加了许多功能。
ApplicationContext的类的实现
ClassPathXmlApplicationContext,FileSystemApplicactionContext:
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
IOC容器的启动是refresh()方法开始的。
这个启动包含BeanDefinition的Resource定位,载入和注册三个基本过程。
1)Resource定位:即BeanDefinition的资源定位,通过ResourceLoaader的Resource接口完成。
2)BeanDefinition的载入:把用户定义的Bean表示成IOC容器的数据结果BeanDefinition。
3)向IOC容器中注入这些BeanDefinition的过程:通过调用BeanDefinitionRegistry接口来完成。
这只是IOC容器初始化过程,不包括Bean依赖注入的过程。在Spring中依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。当然也可以配置lazyinit属性决定是否懒加载bean。
Spring启动一般是通过加载Sping.xml文件启动,我们以ClassPathXmlApplicationContext为例,一般启动方式为:
public class SpringDemoMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
context.start();
}
}
查看ClassPathXmlApplicationContext 的类继承结构:
ClassPathXmlApplicationContext 通过继承实现ResourceLoader已经具备了读取Resource资源的能力。
ClassPathXmlApplicationContext通过以下方法初始化BeanDefinition资源调用,其中refresh()为具体BeanDefinition的载入过程:
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 设置载入spring.xml配置文件
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
refresh() 方法是定义了ApplicationContext的整个初始化过程。其具体为:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备好刷新上下文。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂,以便在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。所有bean定义都已加载,但还没有实例化bean。这允许在特定的ApplicationContext实现中注册特殊的beanpostprocessor等。
// 此时啥都不做
postProcessBeanFactory(beanFactory);
// 调用上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源,国际化
initMessageSource();
// 初始化上下文中的事件机制,时间监听机制初始化
initApplicationEventMulticaster();
// 初始化其他特殊的bean,目前什么都不做
onRefresh();
// 检查监听Bean并且将这些Bean向容器注册,ApplicationListener监听机制
registerListeners();
// 实例化所有的 (non-lazy-init) 单件
finishBeanFactoryInitialization(beanFactory);
// 发布容器事件,结束Refresh过程
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例,以避免挂起资源。
destroyBeans();
// 重置 'active' 标志
cancelRefresh(ex);
throw ex;
}
finally {
// 重置Spring核心中的公共内省缓存,因为我们可能再也不需要单例bean的元数据了……
resetCommonCaches();
}
}
}
prepareRefresh();是一些校验的东西
详细看:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
跟踪obtainFreshBeanFactory()方法:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 此实现对该上下文的底层bean工厂执行实际刷新,关闭前一个bean工厂(如果有的话),并为上下文生命周期的下一阶段初始化一个新的bean工厂。
refreshBeanFactory();
return getBeanFactory();
}
跟踪进入AbstractRefreshableApplicationContext的refreshBeanFactory()方法:
protected final void refreshBeanFactory() throws BeansException {
// 已经有则销毁重启
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 是否允许循环引用,是否允许覆盖Bean定义
customizeBeanFactory(beanFactory);
// 根据工厂创建XmlBeanDefinitionReader,并加装配置文件
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);这个方法就是加载bean并解析的地方吗,更总发现loadBeanDefinitions是一个抽象方法,有多个实现:
如果不知道是哪个,可以debug找出跳转的地方,这里会进入AbstractXmlApplicationContext的loadBeanDefinitions方法:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
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.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
这里主要就是创建一个XML解析工厂(解析我们传入到ClassPathApplicationContext中的参数xml文件),然后解析,解析的具体方法是loadBeanDefinitions, 进入该方法查看:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
其会通过xml解析类 reader.loadBeanDefinitions(configLocations);解析配置文件,继续跟踪最终进入到解析的具体方法是AbstractBeanDefinitionReader的loadBeanDefinitions:
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
其实这还不是最终解析XML的地方,还需要继续跟踪上述方法里的:
int count = loadBeanDefinitions(resources);
最终会进入到XmlBeanDefinitionReader类的loadBeanDefinitions方法中,:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set 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 {
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();
}
}
}
上述方法表示,会将xml配置文件转化为流进行解析,解析的方法是:
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
上述解析过程,就是把流转化为Document对象,在对其进行解析注册bean的过程。所以把流转为Document对象的是
Document doc = doLoadDocument(inputSource, resource);这行代码,当然方面里面的具体的过程,而针对Document对象解析的方法通过
int count = registerBeanDefinitions(doc, resource);这一行代码,还得继续跟踪,查看bean对象解析过程,最终找到DefaultBeanDefinitionDocumentReader类的doRegisterBeanDefinitions方法:
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
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);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("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;
}
然后查看具体解析的方法parseBeanDefinitions:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
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)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
这里就是最终解析xml中各个标签的过程。
在BeanDefinition载入之后,还不能直接使用,需要IOC容器对这些数据进行注册,注册是在DefaultListableBeanFactory中,通过一个HashMap来持有载入的BeanDefinition的:
/** Map of bean definition objects, keyed by bean name. */
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
为什么结果会存入到上述的DefaultListableBeanFactory的beanDefinitionMap 中,通过第二步注册解析的步骤继续跟踪发现:
最终添加到map集合的地方:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
到这里BeanDefinition已经注册到IOC容器中,可以使用了。DefaultListableBeanFactory中存放了整个Bean的配置信息。