Spring菜鳥教你看源碼沖面試
Spring
類的初始化和實例化的不同
IOC
探究spring的IOC容器
DefaultListableBeanFactory
是最終實現類,在代碼中可以找到HashMap的影子;IOC容器就是用HashMap裝的Bean;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { @Nullable private static Class<?> javaxInjectProviderClass; static { try { javaxInjectProviderClass = ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader()); } catch (ClassNotFoundException ex) { // JSR-330 API not available - Provider interface simply not supported then. javaxInjectProviderClass = null; } } /** Map from serialized id to factory instance. */ private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories = new ConcurrentHashMap<>(8); /** Optional id for this factory, for serialization purposes. */ @Nullable private String serializationId; /** Whether to allow re-registration of a different definition with the same name. */ private boolean allowBeanDefinitionOverriding = true; /** Whether to allow eager class loading even for lazy-init beans. */ private boolean allowEagerClassLoading = true; /** Optional OrderComparator for dependency Lists and arrays. */ @Nullable private Comparator<Object> dependencyComparator; /** Resolver to use for checking if a bean definition is an autowire candidate. */ private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE; /** Map from dependency type to corresponding autowired value. */ private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16); /** Map of bean definition objects, keyed by bean name. */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); /** Map from bean name to merged BeanDefinitionHolder. */ private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256); /** Map of singleton and non-singleton bean names, keyed by dependency type. */ private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64); /** Map of singleton-only bean names, keyed by dependency type. */ private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64); /** List of bean definition names, in registration order. */ private volatile List<String> beanDefinitionNames = new ArrayList<>(256); /** List of names of manually registered singletons, in registration order. */ private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16); /** Cached array of bean definition names in case of frozen configuration. */ @Nullable private volatile String[] frozenBeanDefinitionNames; ................ ........... }
BeanFactory:主要方法為getBean(String beanName),該方法根據Bean名稱從容器返回對應的Bean
BeanFactory是接口,提供瞭IOC容器最基本的形式,給具體的IOC容器的實現提供瞭規范,
發現BeanFactory是Spring的IOC容器核心接口,它的職責包括,實例化,有很多的實現類;
原始的BeanFactory無法支持spring的許多插件,如AOP功能、Web應用等
那麼BeanFactroy是否有AOP的影子呢?
找到BeanFactroyAware接口看到很多關鍵字有proxy類似代理的接口
so 猜想是否跟AOP(面向切面,動態代理)有關
然後點進去其中一個方法(AbstractAutoProxyCreator
),發現引入很多跟AOP相關的包
import org.springframework.aop.Advisor; import org.springframework.aop.Pointcut; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyProcessorSupport; import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; import org.springframework.aop.target.SingletonTargetSource;
往下看看這個類,做瞭什麼?找幾個方法出來;
看看類的註釋
此類區分通用攔截器(由創建的所有代理共享)和特定攔截器:每個bean實例唯一。不需要任何通用攔截器。如果存在,則使用interceptorNames屬性設置它們。
與{@link org.springframework.aop.framework.ProxyFactoryBean}一樣,使用當前工廠中的攔截器名稱而不是bean引用來正確處理原型顧問程序和攔截器例如,以支持有狀態的混合。{@link #set InterceptorNames interceptorNames}條目支持任何建議類型。 如果有大量的豆需要用類似的代理包裝,即委托給相同的攔截器,則這種自動代理特別有用。 代替x個目標bean的x個重復代理定義,您可以在bean工廠註冊一個這樣的後處理器,以達到相同的效果
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { /** *設置公共攔截器。這些必須是當前工廠中的bean名稱 */ public void setInterceptorNames(String... interceptorNames) { this.interceptorNames = interceptorNames; } /** 為給定的bean創建一個AOP代理 */ protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); } }
AbstractAutoProxyCreator類關系UML圖
說明AOP橫切在Bean的生命周期中
AOP
Spring 通過 AbstractAutoProxyCreator
來創建 AOP 代理,AbstractAutoProxyCreator 是一個抽象類,它實現瞭 BeanPostProcessor
接口,用於在 bean 初始化完成之後創建它的代理(從上面IOC容器創建Bean過程中有點體現);
在AbstractAutoProxyCreator類關系UML圖中找到一個特殊的接口—>BeanPostProcessor
劃重點:
- 與工廠掛鉤,允許自定義修改新bean實例,如檢查標記接口或使用代理包裝bean
- 普通的
{@code BeanFactory}
允許以編程方式註冊後處理器,並將其應用於通過bean工廠創建的所有bean中;跟上面的AOP橫切BeanFactroy聯系上瞭;
/** 工廠掛鉤,允許自定義修改新bean實例-例如,檢查標記接口或使用代理包裝bean。 <p>通常,通過標記接口*或類似對象填充bean的後處理器將實現{@link #postProcessBeforeInitialization},而使用代理包裝bean的後處理器通常將實現{@link #postProcessAfterInitialization}。 <h3>註冊</h3> <p> {@ code ApplicationContext}可以在其bean定義中自動檢測{@code BeanPostProcessor} bean,並將這些後處理器應用於隨後創建的任何bean。普通的{@code BeanFactory}允許以編程方式註冊後處理器,並將其應用於通過bean工廠創建的所有bean */ public interface BeanPostProcessor { /** 在任何bean 初始化回調(如InitializingBean的{@code afterPropertiesSet} 或自定義的init-method)之前,將此{@code BeanPostProcessor}應用於給定的新bean實例<i> </ i>。該bean將已經用屬性值填充。 返回的bean實例也可能是原始實例的包裝; */ @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** 在任何bean 初始化回調(例如InitializingBean的{@code afterPropertiesSet} 或自定義的初始化方法)之後,將此{@code BeanPostProcessor}應用於給定的新bean實例。該bean將已經用屬性值填充。 返回的bean實例可能是原始實例的包裝。 對於FactoryBean,將為FactoryBean 實例和由FactoryBean創建的對象(從Spring 2.0開始)調用此回調。後處理器可以通過相應的{@code bean instanceof FactoryBean}檢查來決定是應用到FactoryBean還是創建的對象,還是兩者都應用。 */ @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
在來看這張圖(IOC容器工作過程) BeanPostProcessor
就是AOP切入的位置,處在對象的生命周期中;
BeanFactoryPostProcessor(初始化Bean,如上圖)
public interface BeanFactoryPostProcessor { /** 在標準初始化之後,修改應用程序上下文的內部bean工廠。所有bean定義都將被加載,但是還沒有實例化bean *。這甚至可以覆蓋或添加*屬性,甚至可以用於初始化bean。 */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}
另外提點東西(來自面試) BeanFactory 簡介以及它 和FactoryBean的區別(阿裡面試)
FactoryBean接口是什麼?
看看官方註釋:
在BeanFactory中的對象實現的接口,這些對象本身是個單個對象的工廠,如果這些對象實現FactoryBean接口,它將用作對象公開的工廠,而不是直接將自身公開;
好像還是有點蒙吧看看其他解釋
FactoryBean是個Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來進行管理的。但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式類似
FactoryBean接口用的是Class<?> getObjectType();
可以理解為高級定制Bean;
看FactoryBean接口抽象類(AbstractFactoryBean)
public abstract class AbstractFactoryBean<T> implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); private boolean singleton = true; @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); @Nullable private BeanFactory beanFactory; private boolean initialized = false; @Nullable private T singletonInstance; @Nullable private T earlySingletonInstance; /** 設置是否應該創建一個單例,或者在每個請求上創建一個新對象*否則。默認值為{@code true}(單例)。 */ public void setSingleton(boolean singleton) { this.singleton = singleton; } @Override public boolean isSingleton() { return this.singleton; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } @Override public void setBeanFactory(@Nullable BeanFactory beanFactory) { this.beanFactory = beanFactory; } /** 返回運行該bean的BeanFactory */ @Nullable protected BeanFactory getBeanFactory() { return this.beanFactory; } /** 從運行該bean的BeanFactory獲取一個bean類型轉換器 */ protected TypeConverter getBeanTypeConverter() { BeanFactory beanFactory = getBeanFactory(); if (beanFactory instanceof ConfigurableBeanFactory) { return ((ConfigurableBeanFactory) beanFactory).getTypeConverter(); } else { return new SimpleTypeConverter(); } } /** 公開單例實例(用於通過“早期單例”代理訪問)。返回此FactoryBean持有的單例實例 */ @Nullable private T getSingletonInstance() throws IllegalStateException { Assert.state(this.initialized, "Singleton instance not initialized yet"); return this.singletonInstance; } }
看完FactoryBean接口抽象類(AbstractFactoryBean)基本的代碼後,發現什麼?
FactoryBean基於BeanFactory,FactoryBean是一個能生產或者修飾對象生成的工廠Bean;
FactoryBean中定義瞭一個Spring Bean的很重要的三個特性:是否單例、Bean類型、Bean實例
ApplicationContext接口,
由BeanFactory接口派生而來
看到ApplicationContext
接口
提供應用程序配置的中央接口。在應用程序運行時為隻讀,但如果實現支持,則可以重新加載。
ApplicationContext提供:
- 用於訪問應用程序組件的Bean工廠方法。繼承自{@link org.springframework.beans.factory.ListableBeanFactory}。
- 以通用方式加載文件資源的能力。繼承自{@link org.springframework.core.io.ResourceLoader}接口。
- 將事件發佈到註冊的偵聽器的能力。繼承自{@link ApplicationEventPublisher}接口。
- 解決消息的能力,支持國際化。繼承自{@link MessageSource}接口。
- 從父上下文繼承。在後代上下文中的定義將始終優先。例如,這意味著整個Web應用程序都可以使用單個父上下文,而每個servlet都有自己的子上下文,而該子上下文獨立於任何其他servlet的子上下文。
- 除瞭標準的{@link org.springframework.beans.factory.BeanFactory}生命周期功能之外,ApplicationContext實現還檢測並調用{@link ApplicationContextAware} Bean以及{@link ResourceLoaderAware },{@link ApplicationEventPublisherAware}和{@link MessageSourceAware} bean。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /** 返回此應用程序上下文的唯一ID */ @Nullable String getId(); /** 返回此上下文所屬的已部署應用程序的名稱 */ String getApplicationName(); /** 返回此上下文的顯示名稱 */ String getDisplayName(); /** 返回首次加載此上下文時的時間戳 */ long getStartupDate(); /** 返回父級上下文,如果沒有父級,則返回{@code null} */ @Nullable ApplicationContext getParent(); /** 針對此上下文公開AutowireCapableBeanFactory功能。 * <p>應用程序代碼通常不使用此功能,除非是為瞭*初始化存在於應用程序上下文之外的bean實例,*將Spring bean生命周期(全部或部分)應用於它們。 * <p>或者,通過{@link ConfigurableApplicationContext}接口公開的內部BeanFactory也提供對{{link AutowireCapableBeanFactory}接口的訪問。本方法主要*用作ApplicationContext接口上的便捷特定工具。 * <p> <b>註意:從4.2開始,在關閉應用程序上下文之後,此方法將始終拋出IllegalStateException *。</ b>在當前的Spring Framework *版本中,隻有可刷新的應用程序上下文才具有這種行為;從4.2開始,*所有應用程序上下文實現都將必須遵守。 * @為此上下文返回AutowireCapableBeanFactory *如果上下文不支持{@link AutowireCapableBeanFactory}接口,或者尚不具有支持自動連線功能的bean工廠,則拋出IllegalStateException(例如,如果{@code refresh()}具有*從未調用過),或者上下文已經關閉* @see ConfigurableApplicationContext#refresh()* @see ConfigurableApplicationContext#getBeanFactory()* / */ AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
ApplicationContext接口UML類圖
ApplicationContext有兩個主要的實現類:ClassPathXmlApplicationContext:默認從類路徑加載配置文件,還有FileSystemXmlApplicationContext:默認從文件系統中裝載配置文件
WebApplicationContext
提供Web應用程序配置的界面
。在應用程序運行時為隻讀,但是如果實現支持,則可以重新加載。此接口在通用ApplicationContext接口中添加瞭一個{@code getServletContext()}方法
,並定義瞭一個眾所周知的應用程序屬性名稱,該名稱必須在引導過程中綁定到根上下文。類似於通用應用程序上下文,Web應用程序上下文是分層的。 每個應用程序隻有一個根上下文,而應用程序中的每個servlet(包括MVC框架中的調度程序servlet)都有自己的子上下文
。除瞭標準的應用程序上下文生命周期功能外,WebApplicationContext實現還需要檢測{@link ServletContextAware} bean,並相應地調用{@code setServletContext}
方法
public interface WebApplicationContext extends ApplicationContext { /** Context屬性,用於在成功啟動時將根WebApplicationContext綁定到該屬性。 * <p>註意:如果根上下文的啟動失敗,則此屬性可以包含*異常或錯誤作為值。使用WebApplicationContextUtils方便*查找根WebApplicationContext。 */ String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; /** 請求范圍的范圍標識符:“ request”。 *除瞭標準范圍“ singleton”和“ prototype”之外,還受支持。 */ String SCOPE_REQUEST = "request"; /** 會話范圍的范圍標識符:“session”。 *除瞭標準范圍“ singleton”和“ prototype”之外,還受支持。 */ String SCOPE_SESSION = "session"; /** 全局Web應用程序范圍的范圍標識符:“application”。 *除瞭標準范圍“ singleton”和“ prototype”之外,還受支持。 */ String SCOPE_APPLICATION = "application"; /** 工廠中ServletContext環境Bean的名稱 */ String SERVLET_CONTEXT_BEAN_NAME = "servletContext"; /** 工廠中ServletContext init-params環境Bean的名稱 */ String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters"; /** 工廠中ServletContext屬性環境bean的名稱 */ String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes"; /** 返回此應用程序的標準Servlet API ServletContext */ @Nullable ServletContext getServletContext(); }
WebApplicationContext的UML類圖(從圖中可以發現WebApplicationContext擴展瞭ApplicationContext的功能,ApplicationContext擴展瞭BeanFactory的功能。)
這幾個接口間的區別
BeanFactory和ApplicationContext, WebApplicationContext初始化區別:BeanFactory在初始化容器時並沒有實例化Bean,而是在第一次訪問到目標Bean時才實例化該Bean;而ApplicationContext會在初始化上下文時實例化所有的單例的Bean。WebApplicationContext的初始化需要servletContext實例(getServletContext();
),即初始化需要擁有web容器,我們需要在web.xml中配置自啟動的servlet或web容器監聽器(servletContextListener)
Bean的作用域
在BeanFactory和ApplicationContext中的Bean的作用域有兩種:
singleton和prototype,
在WebApplicationContext中的Bean的作用域有三種:request,session和globalSession。
singleton:在IOC容器中僅存在一個Bean實例,Bean以單例方式存在,外部引用都指向這個Bean
prototype:每次調用Bean都返回一個新實例
request:在同一個Http請求的Bean相同,每個Http請求創建一個新的Bean。
session:在Http請求對應同一個session時對應同一個Bean。
globalSession:一般的web應用中globalSession等價於session,隻有在portlet web應用中才存在globalSession概念。
到此這篇關於Spring菜鳥教你看源碼沖面試的文章就介紹到這瞭,更多相關Spring源碼內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 基於Spring上下文工具類 ApplicationContextUtil
- Spring IOC容器FactoryBean工廠Bean實例
- spring的13個經典面試題
- Spring容器中添加bean的5種方式
- 獲取Spring的上下文環境ApplicationContext的最簡單方式