Spring菜鳥教你看源碼沖面試
Spring
類的初始化和實例化的不同

IOC
探究spring的IOC容器
DefaultListableBeanFactory是最終實現(xiàn)類,在代碼中可以找到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),該方法根據(jù)Bean名稱從容器返回對應(yīng)的Bean
BeanFactory是接口,提供了IOC容器最基本的形式,給具體的IOC容器的實現(xiàn)提供了規(guī)范,

發(fā)現(xiàn)BeanFactory是Spring的IOC容器核心接口,它的職責(zé)包括,實例化,有很多的實現(xiàn)類;

原始的BeanFactory無法支持spring的許多插件,如AOP功能、Web應(yīng)用等

那么BeanFactroy是否有AOP的影子呢?
找到BeanFactroyAware接口看到很多關(guān)鍵字有proxy類似代理的接口
so 猜想是否跟AOP(面向切面,動態(tài)代理)有關(guān)

然后點進(jìn)去其中一個方法(AbstractAutoProxyCreator),發(fā)現(xiàn)引入很多跟AOP相關(guān)的包
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;
往下看看這個類,做了什么?找?guī)讉€方法出來;
看看類的注釋
此類區(qū)分通用攔截器(由創(chuàng)建的所有代理共享)和特定攔截器:每個bean實例唯一。不需要任何通用攔截器。如果存在,則使用interceptorNames屬性設(shè)置它們。
與{@link org.springframework.aop.framework.ProxyFactoryBean}一樣,使用當(dāng)前工廠中的攔截器名稱而不是bean引用來正確處理原型顧問程序和攔截器例如,以支持有狀態(tài)的混合。{@link #set InterceptorNames interceptorNames}條目支持任何建議類型。 如果有大量的豆需要用類似的代理包裝,即委托給相同的攔截器,則這種自動代理特別有用。 代替x個目標(biāo)bean的x個重復(fù)代理定義,您可以在bean工廠注冊一個這樣的后處理器,以達(dá)到相同的效果
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/**
*設(shè)置公共攔截器。這些必須是當(dāng)前工廠中的bean名稱
*/
public void setInterceptorNames(String... interceptorNames) {
this.interceptorNames = interceptorNames;
}
/**
為給定的bean創(chuàng)建一個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類關(guān)系UML圖

說明AOP橫切在Bean的生命周期中
AOP
Spring 通過 AbstractAutoProxyCreator 來創(chuàng)建 AOP 代理,AbstractAutoProxyCreator 是一個抽象類,它實現(xiàn)了 BeanPostProcessor 接口,用于在 bean 初始化完成之后創(chuàng)建它的代理(從上面IOC容器創(chuàng)建Bean過程中有點體現(xiàn));
在AbstractAutoProxyCreator類關(guān)系UML圖中找到一個特殊的接口—>BeanPostProcessor
劃重點:
- 與工廠掛鉤,允許自定義修改新bean實例,如檢查標(biāo)記接口或使用代理包裝bean
- 普通的
{@code BeanFactory}允許以編程方式注冊后處理器,并將其應(yīng)用于通過bean工廠創(chuàng)建的所有bean中;跟上面的AOP橫切BeanFactroy聯(lián)系上了;
/**
工廠掛鉤,允許自定義修改新bean實例-例如,檢查標(biāo)記接口或使用代理包裝bean。 <p>通常,通過標(biāo)記接口*或類似對象填充bean的后處理器將實現(xiàn){@link #postProcessBeforeInitialization},而使用代理包裝bean的后處理器通常將實現(xiàn){@link #postProcessAfterInitialization}。 <h3>注冊</h3> <p> {@ code ApplicationContext}可以在其bean定義中自動檢測{@code BeanPostProcessor} bean,并將這些后處理器應(yīng)用于隨后創(chuàng)建的任何bean。普通的{@code BeanFactory}允許以編程方式注冊后處理器,并將其應(yīng)用于通過bean工廠創(chuàng)建的所有bean
*/
public interface BeanPostProcessor {
/**
在任何bean 初始化回調(diào)(如InitializingBean的{@code afterPropertiesSet} 或自定義的init-method)之前,將此{(lán)@code BeanPostProcessor}應(yīng)用于給定的新bean實例<i> </ i>。該bean將已經(jīng)用屬性值填充。 返回的bean實例也可能是原始實例的包裝;
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
在任何bean 初始化回調(diào)(例如InitializingBean的{@code afterPropertiesSet} 或自定義的初始化方法)之后,將此{(lán)@code BeanPostProcessor}應(yīng)用于給定的新bean實例。該bean將已經(jīng)用屬性值填充。 返回的bean實例可能是原始實例的包裝。 對于FactoryBean,將為FactoryBean 實例和由FactoryBean創(chuàng)建的對象(從Spring 2.0開始)調(diào)用此回調(diào)。后處理器可以通過相應(yīng)的{@code bean instanceof FactoryBean}檢查來決定是應(yīng)用到FactoryBean還是創(chuàng)建的對象,還是兩者都應(yīng)用。
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
在來看這張圖(IOC容器工作過程) BeanPostProcessor就是AOP切入的位置,處在對象的生命周期中;
BeanFactoryPostProcessor(初始化Bean,如上圖)
public interface BeanFactoryPostProcessor {
/**
在標(biāo)準(zhǔn)初始化之后,修改應(yīng)用程序上下文的內(nèi)部bean工廠。所有bean定義都將被加載,但是還沒有實例化bean *。這甚至可以覆蓋或添加*屬性,甚至可以用于初始化bean。
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}
另外提點東西(來自面試) BeanFactory 簡介以及它 和FactoryBean的區(qū)別(阿里面試)
FactoryBean接口是什么?
看看官方注釋:
在BeanFactory中的對象實現(xiàn)的接口,這些對象本身是個單個對象的工廠,如果這些對象實現(xiàn)FactoryBean接口,它將用作對象公開的工廠,而不是直接將自身公開;

好像還是有點蒙吧看看其他解釋
FactoryBean是個Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來進(jìn)行管理的。但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產(chǎn)或者修飾對象生成的工廠Bean,它的實現(xiàn)與設(shè)計模式中的工廠模式和修飾器模式類似
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;
/**
設(shè)置是否應(yīng)該創(chuàng)建一個單例,或者在每個請求上創(chuàng)建一個新對象*否則。默認(rèn)值為{@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類型轉(zhuǎn)換器
*/
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)基本的代碼后,發(fā)現(xiàn)什么?
FactoryBean基于BeanFactory,F(xiàn)actoryBean是一個能生產(chǎn)或者修飾對象生成的工廠Bean;
FactoryBean中定義了一個Spring Bean的很重要的三個特性:是否單例、Bean類型、Bean實例
ApplicationContext接口,
由BeanFactory接口派生而來
看到ApplicationContext接口
提供應(yīng)用程序配置的中央接口。在應(yīng)用程序運行時為只讀,但如果實現(xiàn)支持,則可以重新加載。
ApplicationContext提供:
- 用于訪問應(yīng)用程序組件的Bean工廠方法。繼承自{@link org.springframework.beans.factory.ListableBeanFactory}。
- 以通用方式加載文件資源的能力。繼承自{@link org.springframework.core.io.ResourceLoader}接口。
- 將事件發(fā)布到注冊的偵聽器的能力。繼承自{@link ApplicationEventPublisher}接口。
- 解決消息的能力,支持國際化。繼承自{@link MessageSource}接口。
- 從父上下文繼承。在后代上下文中的定義將始終優(yōu)先。例如,這意味著整個Web應(yīng)用程序都可以使用單個父上下文,而每個servlet都有自己的子上下文,而該子上下文獨立于任何其他servlet的子上下文。
- 除了標(biāo)準(zhǔn)的{@link org.springframework.beans.factory.BeanFactory}生命周期功能之外,ApplicationContext實現(xiàn)還檢測并調(diào)用{@link ApplicationContextAware} Bean以及{@link ResourceLoaderAware },{@link ApplicationEventPublisherAware}和{@link MessageSourceAware} bean。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
/**
返回此應(yīng)用程序上下文的唯一ID
*/
@Nullable
String getId();
/**
返回此上下文所屬的已部署應(yīng)用程序的名稱
*/
String getApplicationName();
/**
返回此上下文的顯示名稱
*/
String getDisplayName();
/**
返回首次加載此上下文時的時間戳
*/
long getStartupDate();
/**
返回父級上下文,如果沒有父級,則返回{@code null}
*/
@Nullable
ApplicationContext getParent();
/**
針對此上下文公開AutowireCapableBeanFactory功能。 * <p>應(yīng)用程序代碼通常不使用此功能,除非是為了*初始化存在于應(yīng)用程序上下文之外的bean實例,*將Spring bean生命周期(全部或部分)應(yīng)用于它們。 * <p>或者,通過{@link ConfigurableApplicationContext}接口公開的內(nèi)部BeanFactory也提供對{{link AutowireCapableBeanFactory}接口的訪問。本方法主要*用作ApplicationContext接口上的便捷特定工具。 * <p> <b>注意:從4.2開始,在關(guān)閉應(yīng)用程序上下文之后,此方法將始終拋出IllegalStateException *。</ b>在當(dāng)前的Spring Framework *版本中,只有可刷新的應(yīng)用程序上下文才具有這種行為;從4.2開始,*所有應(yīng)用程序上下文實現(xiàn)都將必須遵守。 * @為此上下文返回AutowireCapableBeanFactory *如果上下文不支持{@link AutowireCapableBeanFactory}接口,或者尚不具有支持自動連線功能的bean工廠,則拋出IllegalStateException(例如,如果{@code refresh()}具有*從未調(diào)用過),或者上下文已經(jīng)關(guān)閉* @see ConfigurableApplicationContext#refresh()* @see ConfigurableApplicationContext#getBeanFactory()* /
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
ApplicationContext接口UML類圖

ApplicationContext有兩個主要的實現(xiàn)類:ClassPathXmlApplicationContext:默認(rèn)從類路徑加載配置文件,還有FileSystemXmlApplicationContext:默認(rèn)從文件系統(tǒng)中裝載配置文件
WebApplicationContext
提供Web應(yīng)用程序配置的界面。在應(yīng)用程序運行時為只讀,但是如果實現(xiàn)支持,則可以重新加載。此接口在通用ApplicationContext接口中添加了一個{@code getServletContext()}方法,并定義了一個眾所周知的應(yīng)用程序?qū)傩悦Q,該名稱必須在引導(dǎo)過程中綁定到根上下文。類似于通用應(yīng)用程序上下文,Web應(yīng)用程序上下文是分層的。 每個應(yīng)用程序只有一個根上下文,而應(yīng)用程序中的每個servlet(包括MVC框架中的調(diào)度程序servlet)都有自己的子上下文。除了標(biāo)準(zhǔn)的應(yīng)用程序上下文生命周期功能外,WebApplicationContext實現(xiàn)還需要檢測{@link ServletContextAware} bean,并相應(yīng)地調(diào)用{@code setServletContext}方法
public interface WebApplicationContext extends ApplicationContext {
/**
Context屬性,用于在成功啟動時將根WebApplicationContext綁定到該屬性。 * <p>注意:如果根上下文的啟動失敗,則此屬性可以包含*異?;蝈e誤作為值。使用WebApplicationContextUtils方便*查找根WebApplicationContext。
*/
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
/**
請求范圍的范圍標(biāo)識符:“ request”。 *除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
*/
String SCOPE_REQUEST = "request";
/**
會話范圍的范圍標(biāo)識符:“session”。 *除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
*/
String SCOPE_SESSION = "session";
/**
全局Web應(yīng)用程序范圍的范圍標(biāo)識符:“application”。 *除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
*/
String SCOPE_APPLICATION = "application";
/**
工廠中ServletContext環(huán)境Bean的名稱
*/
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
/**
工廠中ServletContext init-params環(huán)境Bean的名稱
*/
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
/**
工廠中ServletContext屬性環(huán)境bean的名稱
*/
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
/**
返回此應(yīng)用程序的標(biāo)準(zhǔn)Servlet API ServletContext
*/
@Nullable
ServletContext getServletContext();
}
WebApplicationContext的UML類圖(從圖中可以發(fā)現(xiàn)WebApplicationContext擴展了ApplicationContext的功能,ApplicationContext擴展了BeanFactory的功能。)

這幾個接口間的區(qū)別
BeanFactory和ApplicationContext, WebApplicationContext初始化區(qū)別:BeanFactory在初始化容器時并沒有實例化Bean,而是在第一次訪問到目標(biāo)Bean時才實例化該Bean;而ApplicationContext會在初始化上下文時實例化所有的單例的Bean。WebApplicationContext的初始化需要servletContext實例(getServletContext();),即初始化需要擁有web容器,我們需要在web.xml中配置自啟動的servlet或web容器監(jiān)聽器(servletContextListener)
Bean的作用域
在BeanFactory和ApplicationContext中的Bean的作用域有兩種:
singleton和prototype,
在WebApplicationContext中的Bean的作用域有三種:request,session和globalSession。
singleton:在IOC容器中僅存在一個Bean實例,Bean以單例方式存在,外部引用都指向這個Bean
prototype:每次調(diào)用Bean都返回一個新實例
request:在同一個Http請求的Bean相同,每個Http請求創(chuàng)建一個新的Bean。
session:在Http請求對應(yīng)同一個session時對應(yīng)同一個Bean。
globalSession:一般的web應(yīng)用中g(shù)lobalSession等價于session,只有在portlet web應(yīng)用中才存在globalSession概念。
到此這篇關(guān)于Spring菜鳥教你看源碼沖面試的文章就介紹到這了,更多相關(guān)Spring源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談java Iterator.remove()方法的用法(詳解)
下面小編就為大家?guī)硪黄獪\談java Iterator.remove()方法的用法(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01
Java基數(shù)排序radix sort原理及用法解析
這篇文章主要介紹了Java基數(shù)排序radix sort原理及用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
SpringCloud使用AOP統(tǒng)一處理Web請求日志實現(xiàn)步驟
這篇文章主要為大家介紹了SpringCloud使用AOP統(tǒng)一處理Web請求日志實現(xiàn)步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
elasticsearch元數(shù)據(jù)構(gòu)建metadata及routing類源碼分析
這篇文章主要為大家介紹了elasticsearch元數(shù)據(jù)構(gòu)建metadata?routing類內(nèi)部源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04

