Ioc容器初始化流程<
PS:另外这里强调下BeanDefinition的注册与Bean依赖的注入的区别:
BeanDefinition的注册仅仅负责将BeanDefinition放入HashMap中即完成了注册。依赖的注入不是在Ioc容器启动的时候完成的。而是在getBean()实例的时候才
触发依赖的注入。这两个是独立的过程。
关键根据location来定位Resource的地方来了,请看:
至此,从上面classpath*:路径和和:开头的路径下的Resource都找到了。
进入到DefaultBeanDefinitionDocumentReader类看
至此,就开始进行一些标签(import,bean)的解析了。
- Ioc初始化的入口就是refresh方法(可以参看FileSystemXmlApplicationContext类)
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
该refresh方法标志着Ioc容器正式启动。其启动可以分为如下三个步骤:
- Resource定位(由ResourceLoader模块负责)
- BeanDefinition载入,解析(由BeanDefinitionReader模块负责)。将定义好的Bean载入,解析成Ioc容器内部的数据结构(BeanDefinition)。通过这个BeanDefinition,Ioc容器实现对Bean的管理。
- BeanDefinition注册。该过程通过调用BeanDefinitionRegistry接口实现完成。其本质是将解析得到的BeanDefinition放入Ioc容器的HashMap中。
//DefaultListableBeanFactory类中
// Map of bean definition objects, keyed by bean name
private final Map <String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap <String,BeanDefinition>();
BeanDefinition的注册仅仅负责将BeanDefinition放入HashMap中即完成了注册。依赖的注入不是在Ioc容器启动的时候完成的。而是在getBean()实例的时候才
触发依赖的注入。这两个是独立的过程。
- BeanDefinition Resource定位
public int loadBeanDefinitions(String location, Set
<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
//...
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
...
}
}
return loadCount;
}
catch (IOException ex) {
//...
}
}
else {
//....
}
}
关键根据location来定位Resource的地方来了,请看:
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
else {
// all class path resources with the given name
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
// Only look for a pattern after a prefix here
// (to not get fooled by a pattern symbol in a strange prefix).
int prefixEnd = locationPattern.indexOf(":") + 1;
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
至此,从上面classpath*:路径和和:开头的路径下的Resource都找到了。
- BeanDefinition 载入和解析
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) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
上面整个refresh方法就像计算机系统重启一样。我们看简单版本的载入。从XmlBeanFactory的
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
进入到XmlBeanDefinitionReader的
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.getResource());
}
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) {
//....
}
}
再进入到
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
//..
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
上面将Xml配置文件,读取到内存变成一个Xml Document,然后交给BeanDefinitionDocumentReader解析这个Document。
进入到DefaultBeanDefinitionDocumentReader类看
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
至此,就开始进行一些标签(import,bean)的解析了。
- BeanDefinition 注册