赞
踩
上一章节我们讲的是Spirng中的一些核心类,包括IOC容器工厂,和配置解析的一些类,这一章主要是跟一下IOC启动流程。这里我先贴一下IOC的启动部分流程图,在后面的源码分析就是在走这张图,为什么是部分流程图,因为我先分多篇文章来写IOC启动流程,太长了看起来费劲。我把IOC启动流程分为4个阶段:容器创建 -> 配置加载 -> Bean的解析 -> Bean的注册,如下:
源码分析入口从 ClasspathXmlApplicationContext 开始,通过它来加载一个配置
//加载Spring配置文件,拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("配置文件.xml")
//从容器中拿到对象实例
MyBean myBean = context.getBean(MyBean.class);
进入ClassPathXmlApplicationContext构造器可以看到,该构造器接收一个配置文件,构造器的注释是这一样描述的:创建一个新的 ClassPathXmlApplicationContext,从给定的 XML 文件加载定义并自动刷新上下文。
/** 创建一个新的 ClassPathXmlApplicationContext,从给定的 XML 文件加载定义并自动刷新上下文。 * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */ public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } /** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */ public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { //调用父类的构造器 super(parent); //设置位置文件地址 setConfigLocations(configLocations); if (refresh) { //刷新容器【重点】 refresh(); } }
在ClasspathXmlApplication的构造器中做了如下事情:
ResourcePatternResolver
setConfigLocations
方法保存好配置文件地址,refresh()
刷新容器ResourcePatternResolver是Bean的资源加载器 ,通过父容器 AbstractApplicationContext 中的构造方法创建:
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext public AbstractApplicationContext(@Nullable ApplicationContext parent) { //加载 resourcePatternResolver this(); // setParent(parent); } /** * Create a new AbstractApplicationContext with no parent. */ //创建一个AbstractApplicationContext容器工厂,并构建一个ResourcePatternResolver public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } //获取 PathMatchingResourcePatternResolver protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); } public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); //资源加载器 this.resourceLoader = resourceLoader; }
父容器AbstractApplicationContext 继承了 DefaultResourceLoader ,拥有资源加载的能力,在构造器中中创建了ResourcePatternResolver,使用的是PathMatchingResourcePatternResolver
作为实现,它能够将指定的资源位置路径解析为一个或多个匹配的资源。
下面是ResourceLoader 源码:
public interface ResourceLoader { //默认从classpath中加载资源文件 /** Pseudo URL prefix for loading from the class path: "classpath:". */ String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; //把资源文件转换成Resource Resource getResource(String location); ClassLoader getClassLoader(); } public interface ResourcePatternResolver extends ResourceLoader { //从classpath加载资源 String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; //把文件转换成Resource[] ,对ResourceLoader做了扩展 Resource[] getResources(String locationPattern) throws IOException; }
然后就是保存配置地址 ,从源码可以看出,我们是可以传入多个配置文件给容器的。
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext implements BeanNameAware, InitializingBean { //地址保存到这里 @Nullable private String[] configLocations; /** * Set the config locations for this application context. * <p>If not set, the implementation may use a default as appropriate. */ //可以传入多个配置 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++) { this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
ClasspathXmlApplication调用 AbstractApplicationContext#refresh 方法刷新容器,该方法中实现了IOC容器的整个初始化过程。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //准备刷新工作 ,记录开始时间,初始化属性,校验配置文件,准备事件的存储Set prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //告诉子类,刷新Bean工厂,销毁旧beanFactory,创建新beanFactory,默认DefaultListableBeanFactory //从子容器的refreshBeanFactory方法中载入Bean的资源文件 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //准备工厂,配置工厂的下文特性, 例如上下文的 ClassLoader 和后处理器。Bean表达式解析器, //BeanPostProcessor和 Aware类的自动装配等 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //BeanFactory初始化完成的后置工作,这是一个空方法,留给三方框架或者自己配置,作用是允许对beanFoctory进行扩展处理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //调用BeanFactory的后置处理器BeanFactoryPostProcessor,在 bean定义注册之后bean实例化之前调用 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //注册Bean的后置处理器BeanPostProcessor,在Bean初始化前,后执行 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //初始化信息源,国际化相关 initMessageSource(); // Initialize event multicaster for this context. //初始化容器事件传播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //空方法,该方法子类实现,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器 onRefresh(); // Check for listener beans and register them. //注册事件监听器,注册实现了ApplicationListener接口的监听器bean, //这些监听器是注册到ApplicationEventMulticaster中的 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //实例化所有剩余的(非延迟初始化)单例的Bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent) 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. //销毁已经创建的单例Bean。 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()方法主要是通过子类 refreshBeanFactory()
方法加载Bean信息,然后就是一些列的容器生命周期事件。这里其实是用到了模板设计模式
,在refresh()方法中指定容器刷新流程,很多的细节步骤由子类去实现。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新工厂,有子类实现
refreshBeanFactory();
//通过子类返回工厂,默认 DefaultListableBeanFactory
return getBeanFactory();
}
这里只是定义了抽象方法,refreshBeanFactory由子类实现,见:AbstractRefreshableApplicationContext#refreshBeanFactory
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { //如果已经有BeanFactory,销毁Bean,关闭容器 destroyBeans(); closeBeanFactory(); } try { //创建IOC容器 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //定制BeanFactory,如设置启动参数,开启注解的自动装配等 customizeBeanFactory(beanFactory); //载入Bean,由子类实现 loadBeanDefinitions(beanFactory); this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
该方法中先判断如果已经存在BeanFactory就销毁掉重新创建,默认使用的是DefaultListableBeanFactory
作为BeanFactory,并loadBeanDefinitions方法加载Bean,方法由子类 AbstractXmlApplicationContext#loadBeanDefinitions
实现。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //创建 XmlBeanDefinitionReader ,用来从XML中读取Bean XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. //把Environment 和 ResourceLoader 设置给beanDefinitionReader beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); //设置Sax解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //初始化Bean的读取器,启用 Xml 的校验机制 , 允许子类自定义初始化读取器 initBeanDefinitionReader(beanDefinitionReader); //加载Bean, XmlBeanDefinitionReader真正实现加载逻辑 loadBeanDefinitions(beanDefinitionReader); }
loadBeanDefinitions方法是用来加载Bean的,创建了XmlBeanDefinitionReader 基于XML的Bean的读取器,最终会调用 XmlBeanDefinitionReader.(configLocations)
从配置中加载Bean,见:AbstractXmlApplicationContext#loadBeanDefinitions(.XmlBeanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //获取配置的Resource Resource[] configResources = getConfigResources(); //如果有Resrouce就调用 XmlBeanDefinitionReader.loadBeanDefinitions 加载Bean if (configResources != null) { //Xml Bean 读取器调用其父类 AbstractBeanDefinitionReader 读取定位的 Bean 配置资源 reader.loadBeanDefinitions(configResources); } // 如果子类中获取的 Bean 配置资源Resource为空, // 则获取 ClassPathXmlApplicationContext 构造方法中 setConfigLocations 方法设置的资源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //Xml Bean 读取器调用其父类 AbstractBeanDefinitionReader 读取定位的 Bean 配置资源 reader.loadBeanDefinitions(configLocations); } }
这里先尝试获取配置资源Resource,如果为空就通过指定配置reader.loadBeanDefinitions(configLocations);
加载Bean,最终调用父类:AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)
方法
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //资源加载器,在初始化IOC容器的时候创建的 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,加载多个 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); //委派 XmlBeanDefinitionReader加载Bean 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 resource = resourceLoader.getResource(location); //委派 XmlBeanDefinitionReader加载Bean int count = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location [" + location + "]"); } return count; } }
在该方法中显示得到初始化容器时创建的ResourceLoader,通过ResourceLoader.getResource(location)
得到Resource资源对象后,调用loadBeanDefinitions(resources);
方法,其实是委派XmlBeanDefinitionReader
去加载Bean。程序最终来到XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)
方法
//对 Resource进行了编码 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } 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<EncodedResource> 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 { //从Resource中得到输入流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //从输入流中得到XML配置文件源 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //加载BeanDefinitions , 加载Bean的核心方法 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { //输入流关闭 inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { //删除Resource currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
XmlBeanDefinitionReader#loadBeanDefinitions
对配置文件做了编码处理后,从Resource中得到输入流,然后包装成 InputSource(XML数据源),调用 doLoadBeanDefinitions
方法去加载Bean,见:XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将 XML 文件转换为 Document 对象,通过 documentLoader来解析
Document doc = doLoadDocument(inputSource, resource);
//【重要】解析和注册Bean的消息流程
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
...省略...
XmlBeanDefinitionReader 通过 DefaultDocumentLoader#loadDocument
把InputResource转成Document对象,然后委派 BeanDefinitionParserDelegate
去解析Document然后注册Bean。
文章就先到这里结束把,下一章接上Bean的解析和Bean的注册,如果喜欢就给个好评吧,你的肯定是我最大的动力~ 文章数量突破100啦~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。