分为三步,定位、加载、注册
第一步:定位
1. 开始,从配置文件找入口
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
2. 所以,从ClassPathXmlApplicationContext类开始,找到源码中对应的构造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); }
3. 按住Ctrl+鼠标左键,点击上面的this,跳入到构造方法中
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations);//进入支线 if (refresh) { //重启、刷新、重置 refresh(); } }
4. 在setConfigLocations方法上,按Ctrl+鼠标左键,会进入下一个抽象类 AbstractRefreshableConfigApplicationContext
//解析Bean定义资源文件的路径,处理多个资源文件字符串数组 public void setConfigLocations(@Nullable String... locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { // resolvePath为同一个类中将字符串解析为路径的方法 this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
5. 接着Ctrl+Alt+左方向键回到ClassPathXmlApplicationContext方法,进入refresh方法
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //进入obtainFreshBeanFactory()方法 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//进入主线 // Prepare the bean factory for use in this context. //为BeanFactory配置容器特性,例如类加载器、事件处理器等 prepareBeanFactory(beanFactory); //省略其他代码 } }
6. 在obtainFreshBeanFactory方法上,按Ctrl+鼠标左键,进入AbstractApplicationContext类的obtainFreshBeanFactory方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法 refreshBeanFactory();//进入主线 按住 Ctrl+Alt+B 找抽象类-->AbstractRefreshableApplicationContext ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
7. 通过obtainFreshBeanFactory方法里面的找到refreshBeanFactory方法按住 Ctrl+Alt+B 进入抽象类,AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException { //如果已经有容器,销毁容器中的bean,关闭容器 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //创建IOC容器 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等 customizeBeanFactory(beanFactory); //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器 loadBeanDefinitions(beanFactory);//进入主线 Ctrl+Alt+B 从定位进入加载的过程 AbstractXmlApplicationContext 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类
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容 器使用该读取器读取Bean定义资源 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的 //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器 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的校验机制 initBeanDefinitionReader(beanDefinitionReader); //Bean读取器真正实现加载的方法 loadBeanDefinitions(beanDefinitionReader); //进入主线 调用了自己的重载方法 }
8. 点击loadBeanDefinitions(beanDefinitionReader)方法进入重载的方法,loadBeanDefinitions(XmlBeanDefinitionReader reader)
//Xml Bean读取器加载Bean定义资源 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //获取Bean定义资源的定位 Resource[] configResources = getConfigResources(); if (configResources != null) { //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位 //的Bean定义资源 reader.loadBeanDefinitions(configResources); //进入主线 ctrl+鼠标左键 } //如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位 //的Bean定义资源 reader.loadBeanDefinitions(configLocations); } }
9. 按住ctrl+鼠标左键进入AbstractBeanDefinitionReader中的loadBeanDefinitions方法。
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource);//进入主线 Ctrl+Alt+B 进入 XmlBeanDefinitionReader 类 } return counter; }
10. ,在loadBeanDefinitions(resource)方法上,按住Ctrl+Alt+B 进入 XmlBeanDefinitionReader类
//XmlBeanDefinitionReader加载资源的入口方法 @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //将读入的XML资源进行特殊编码处理 return loadBeanDefinitions(new EncodedResource(resource)); }
进入入本身重载方法
//这里是载入XML形式Bean定义资源文件方法 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); //省略if... try { //将资源文件转为InputStream的IO流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //从InputStream中得到XML的解析源 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // 进入主线 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { //关闭从Resource中得到的IO流 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(); } } }
11. 点击进入doLoadBeanDefinitions方法
//从特定XML文件中实际载入Bean定义资源的方法 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //将XML文件转换为DOM对象,解析过程由documentLoader实现 Document doc = doLoadDocument(inputSource, resource); //这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则 return registerBeanDefinitions(doc, resource);//进入主线 } catch (BeanDefinitionStoreException ex) { throw ex; } //省略抛异常 }
12. 进入registerBeanDefinitions方法,点击registerBeanDefinitions方法,进入注册类DefaultBeanDefinitionDocumentReader
//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //获得容器中注册的Bean数量 int countBefore = getRegistry().getBeanDefinitionCount(); //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口, //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //进入主线 Ctrl+Alt+B点进去 //统计解析的Bean数量 return getRegistry().getBeanDefinitionCount() - countBefore; }
第三步:注册
//根据Spring DTD对Bean的定义规则解析Bean定义Document对象 @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { //获得XML描述符 this.readerContext = readerContext; logger.debug("Loading bean definitions"); //获得Document的根元素 Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root);//进入主线 }
13. 进入doRegisterBeanDefinitions方法
protected void doRegisterBeanDefinitions(Element root) { //具体的解析过程由BeanDefinitionParserDelegate实现, //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素 BeanDefinitionParserDelegate parent = this.delegate; //委派类 this.delegate = createDelegate(getReaderContext(), root, parent); //省略if... //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性 preProcessXml(root); //从Document的根元素开始进行Bean定义的Document对象 parseBeanDefinitions(root, this.delegate); //进入主线 //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性 postProcessXml(root); this.delegate = parent; }
14. 进入parseBeanDefinitions方法
//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean定义的Document对象使用了Spring默认的XML命名空间 if (delegate.isDefaultNamespace(root)) { //获取Bean定义的Document对象根元素的所有子节点 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //获得Document节点是XML元素节点 if (node instanceof Element) { Element ele = (Element) node; //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间 if (delegate.isDefaultNamespace(ele)) { //使用Spring的Bean规则解析元素节点 parseDefaultElement(ele, delegate);// 进入主线 } else { //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的 //解析规则解析Document根节点 delegate.parseCustomElement(root); } }
15. 进入parseDefaultElement方法,
//使用Spring的Bean规则解析Document元素节点 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规则解析元素 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate);//进入主线 跟着委派走 } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
16. 进入processBeanDefinition方法,进入BeanDefinitionParserDelegate类,
//解析<Bean>元素的入口 @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); }
17. 进入重载方法parseBeanDefinitionElement
//解析Bean定义资源Document对象的普通元素 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //进入支线 // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类 //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现 // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向Spring IOC容器注册解析得到的Bean定义,这是Bean定义向IOC容器注册的入口BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());//进入主线,点这里 registerBeanDefinition } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. //在完成向Spring IOC容器注册解析得到的Bean定义之后,发送注册事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
18. 进入BeanDefinitionReaderUtils的registerBeanDefinition方法
//将解析的BeanDefinitionHold注册到容器中 public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. //获取解析的BeanDefinition的名称 String beanName = definitionHolder.getBeanName(); //向IOC容器注册BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 主线,点这里 // Register aliases for bean name, if any. //如果解析的BeanDefinition有别名,向容器为其注册别名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
19. 点击registry.registerBeanDefinition()选择DefaultListableBeanFactory类,进入registerBeanDefinition()方法,给beanDefinitionMap赋值
//向IOC容器注册解析的BeanDefiniton @Override 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"); //校验解析的BeanDefiniton if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { //省略if判断 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<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> 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; } //检查是否有同名的BeanDefinition已经在IOC容器中注册 if (oldBeanDefinition != null || containsSingleton(beanName)) { //重置所有已经注册过的BeanDefinition的缓存 resetBeanDefinition(beanName); } }