看這篇文章以前能夠先了解以前的跟蹤流程,https://www.jianshu.com/p/4934233f0eadjava
代碼過寬,能夠shift + 鼠標滾輪 左右滑動查看web
AbstractApplicationContext類refresh()方法中的第四個調用方法postProcessBeanFactory()的跟蹤。spring
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { // Allows post-processing of the bean factory in context subclasses. // 容許在上下文的子類中對bean factory進行後處理 postProcessBeanFactory(beanFactory); ··· }
斷點進入跟蹤。express
此方法的實如今AbstractRefreshableWebApplicationContext類中,它是XmlWebApplicationContext的父類。進入方法查看:編程
/** * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc. * * 註冊request/session scopes,一個ServletContextAwareProcessor處理器等。 */ @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //ServletContextAwareProcessor中拿到應用上下文持有的servletContext引用和servletConfig引用 //1.添加ServletContextAwareProcessor處理器 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); //在自動注入時忽略指定的依賴接口 //一般被應用上下文用來註冊以其餘方式解析的依賴項 beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); //2.註冊web應用的scopes WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); //3.註冊和環境有關的beans WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); }
postProcessBeanFactory方法的接口聲明在AbstractApplicationContext類中:緩存
/** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for registering special * BeanPostProcessors etc in certain ApplicationContext implementations. * * 在應用上下文的內部bean factory初始化以後修改bean factory。 * 全部的bean definitions已經被加載,可是尚未bean被實例化。 * 在明確的ApplicationContext實現中容許指定BeanPostProcessors等的註冊 */ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { }
跟蹤標記爲1的方法session
此方法的實如今AbstractBeanFactory類中app
這裏要註冊的處理器ServletContextAwareProcessor帶有Aware單詞,這個單詞是「有意識、能意識到」的意思,我的理解就是能意識到ServletContext的存在,也就是能拿到ServletContext的引用,或者能對其進行設置。webapp
//1.添加ServletContextAwareProcessor處理器 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); /** * Add a new BeanPostProcessor that will get applied to beans created * by this factory. To be invoked during factory configuration. * <p>Note: Post-processors submitted here will be applied in the order of * registration; any ordering semantics expressed through implementing the * {@link org.springframework.core.Ordered} interface will be ignored. Note * that autodetected post-processors(e.g. as beans in an ApplicationContext) * will always be applied after programmatically registered ones. * * 添加一個新的BeanPostProcessor,在工廠建立bean的時候會應用獲得。 * 在工廠配置時被調用。 * 注意:Post-processors是按照註冊的順序被提交的 * 任何經過實現Ordered接口的排序表達式都將被忽略。 * 注意,自動檢測的post-processors(做爲一個在ApplicationContext的bean)老是在編程方式註冊後纔會被使用。 */ @Override public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) { Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null"); //beanPostProcessors是一個ArrayList,持有在建立bean時被應用的BeanPostProcessors this.beanPostProcessors.remove(beanPostProcessor); this.beanPostProcessors.add(beanPostProcessor); //InstantiationAwareBeanPostProcessor這個接口有兩個方法 //一個在實例化以前被調用 //一個在實例化以後,初始化以前被調用,能夠用來作一些特殊用途,好比代理 if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) { this.hasInstantiationAwareBeanPostProcessors = true; } //DestructionAwareBeanPostProcessor這個接口只有一個方法,在被銷燬前調用 if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) { this.hasDestructionAwareBeanPostProcessors = true; } }
跟蹤標記爲2的方法ide
此方法的實如今WebApplicationContextUtils類中
//2.註冊web應用的scopes WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); /** * Register web-specific scopes ("request", "session", "globalSession", "application") * with the given BeanFactory, as used by the WebApplicationContext. * * 註冊web特有的scopes("request", "session", "globalSession", "application")到指定的bean工廠 * 被WebApplicationContext使用 */ public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) { //2.1註冊request Scope beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); //註冊session Scope beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false)); //註冊global session Scope beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true)); if (sc != null) { ServletContextScope appScope = new ServletContextScope(sc); //註冊application Scope beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register as ServletContext attribute, for ContextCleanupListener to detect it. // 爲了能讓ContextCleanupListener監聽器檢測到, // 將application Scope做爲ServletContext的屬性進行註冊 sc.setAttribute(ServletContextScope.class.getName(), appScope); } //ServletRequest.class爲key,對象爲value放入到了beanFactory的resolvableDependencies屬性中 //resolvableDependencies是一個ConcurrentHashMap,映射依賴類型和對應的被注入的value //value要是依賴類型的實例,要不value就應該是個ObjectFactory //ObjectFactory和FactoryBean的區別能夠看下文參考 beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); //是否存在jsf if (jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } }
跟蹤標記爲2.1的方法
此方法的實如今AbstractBeanFactory類中
//2.1註冊request Scope beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); @Override public void registerScope(String scopeName, Scope scope) { Assert.notNull(scopeName, "Scope identifier must not be null"); Assert.notNull(scope, "Scope must not be null"); //singleton和prototype在這個方法中不進行註冊 if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) { //不能替換已存在的 singleton scope和 prototype scope throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'"); } //scopes是AbstractBeanFactory的LinkedHashMap屬性 Scope previous = this.scopes.put(scopeName, scope); //打印日誌 if (previous != null && previous != scope) { //對已經註冊過的scope進行替換 if (logger.isInfoEnabled()) { logger.info("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]"); } } else { //沒註冊過的和同一個實例註冊兩次的scope都打印日誌記錄下 if (logger.isDebugEnabled()) { logger.debug("Registering scope '" + scopeName + "' with implementation [" + scope + "]"); } } }
跟蹤標記爲3的方法
此方法的實如今WebApplicationContextUtils類中
//3.註冊和環境有關的beans WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); /** * Register web-specific environment beans ("contextParameters", "contextAttributes") * with the given BeanFactory, as used by the WebApplicationContext. * * 註冊web特有的environment beans ("contextParameters", "contextAttributes")到指定工廠中 * 被WebApplicationContext所使用 */ public static void registerEnvironmentBeans( ConfigurableListableBeanFactory bf, ServletContext servletContext, ServletConfig servletConfig) { //單例或者beanDefinition中不包含servletContext進入條件 if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) { //3.1註冊servletContext單例,註冊方法跟蹤過一次,這裏再跟蹤一次加深印象 bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext); } //單例或者beanDefinition中不包含servletConfig進入條件 if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) { //註冊servletConfig單例 bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig); } //單例或者beanDefinition中不包含contextParameters進入條件 if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) { Map<String, String> parameterMap = new HashMap<String, String>(); if (servletContext != null) { Enumeration<?> paramNameEnum = servletContext.getInitParameterNames(); while (paramNameEnum.hasMoreElements()) { String paramName = (String) paramNameEnum.nextElement(); //將servletContext參數配置放入集合中 //也就是web.xml中context-param標籤裏的param-name和param-value parameterMap.put(paramName, servletContext.getInitParameter(paramName)); } } if (servletConfig != null) { Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames(); while (paramNameEnum.hasMoreElements()) { String paramName = (String) paramNameEnum.nextElement(); //將servletConfig中的參數配置放入集合 parameterMap.put(paramName, servletConfig.getInitParameter(paramName)); } } //以contextParameters做爲name,集合轉換成不可修改狀態,做爲value,進行註冊 bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME, Collections.unmodifiableMap(parameterMap)); } //單例或者beanDefinition中不包含contextAttributes進入條件 if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) { Map<String, Object> attributeMap = new HashMap<String, Object>(); if (servletContext != null) { Enumeration<?> attrNameEnum = servletContext.getAttributeNames(); while (attrNameEnum.hasMoreElements()) { String attrName = (String) attrNameEnum.nextElement(); //將servletContext中設置的Attribute放入集合 attributeMap.put(attrName, servletContext.getAttribute(attrName)); } } //以contextAttributes做爲name,集合轉換成不可修改狀態,做爲value,進行註冊 bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap)); } }
跟蹤標記爲3.1的方法
此方法的實如今DefaultListableBeanFactory類中
//3.1註冊servletContext單例 bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext); @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { //3.1.1調用父類方法,註冊單例 super.registerSingleton(beanName, singletonObject); //AbstractBeanFactory類中有個集合屬性alreadyCreated //裏面保存在至少被建立過一次的beanName //若是這個集合中存在beanName,那麼說明已經進入了bean建立階段 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) // 沒法再修改啓動時集合元素(爲了穩定迭代) synchronized (this.beanDefinitionMap) { //beanName不在beanDefinitionMap中,說明是手動註冊 if (!this.beanDefinitionMap.containsKey(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1); updatedSingletons.addAll(this.manualSingletonNames); updatedSingletons.add(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase // 仍然處於啓動註冊階段 if (!this.beanDefinitionMap.containsKey(beanName)) { //屬於手動註冊狀況 this.manualSingletonNames.add(beanName); } } //進入這個方法查看 clearByTypeCache(); } /** * Remove any assumptions about by-type mappings. * * 刪除按照類型映射有關的任何假設 */ private void clearByTypeCache() { //allBeanNamesByType是單例和非單例beanName的映射,key是依賴類型 this.allBeanNamesByType.clear(); //僅單例beanName的映射,key是依賴類型 this.singletonBeanNamesByType.clear(); }
跟蹤標記爲3.1.1的方法
此方法的實如今DefaultSingletonBeanRegistry類中
//2.1調用父類方法,註冊單例 super.registerSingleton(beanName, singletonObject); /** * Register the given existing object as singleton in the bean registry, * under the given bean name. * <p>The given instance is supposed to be fully initialized; the registry * will not perform any initialization callbacks (in particular, it won't * call InitializingBean's {@code afterPropertiesSet} method). * The given instance will not receive any destruction callbacks * (like DisposableBean's {@code destroy} method) either. * <p>When running within a full BeanFactory: <b>Register a bean definition * instead of an existing instance if your bean is supposed to receive * initialization and/or destruction callbacks.</b> * <p>Typically invoked during registry configuration, but can also be used * for runtime registration of singletons. As a consequence, a registry * implementation should synchronize singleton access; it will have to do * this anyway if it supports a BeanFactory's lazy initialization of singletons. * * 在給定的bean name下,將存在的對象做爲單例註冊在工廠中 * 給定的實例應該是徹底初始化;工廠不執行任何初始化回調(特別是,他不會調用InitializingBean的 * afterPropertiesSet方法) * 給定的實例也不接收任何銷燬回調(像DisposableBean的destroy方法) * 當在完整的BeanFactory運行時: * 若是你的bean須要接收初始化或者銷燬的回調,註冊一個bean definition替代一個存在的實例 * 一般此方法在工廠配置時被調用,也能在運行時單例註冊時被調用。 * 做爲結果,工廠的實現應該同步單例的訪問;若是支持BeanFactory的單例的延遲初始化就不得不這樣作 */ @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object oldObject = this.singletonObjects.get(beanName); //不能註冊兩次 if (oldObject != null) { throw new IllegalStateException("Could not register object [" + singletonObject + "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); } //進入這個方法 addSingleton(beanName, singletonObject); } } /** * Add the given singleton object to the singleton cache of this factory. * <p>To be called for eager registration of singletons. * * 添加給定單例對象到工廠的單例緩存中 * 用來被提前註冊的單例調用 */ protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { //singletonObjects是一個ConcurrentHashMap //用來緩存單例對象 this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); //singletonFactories是一個HashMap //裏面緩存着單例工廠 this.singletonFactories.remove(beanName); //早期單例對象 //earlySingletonObjects是一個HashMap this.earlySingletonObjects.remove(beanName); //registeredSingletons是一個LinkedHashSet //被註冊單例的集合,以註冊的順序包含着bean name this.registeredSingletons.add(beanName); } }
postProcessBeanFactory方法也跟蹤完了。
未完···
FactoryBean與ObjectFactory區別:
https://blog.csdn.net/m0_38043362/article/details/80284577
——————————————————————————————————
request
session
globalSession
Scopeapplication
。同時在ServletContext 的屬性中保存一份。——————————————————————————————————