使用示例
讀源碼先從最簡單的使用示例入手,然後一層一層往下探索,下面先寫一個典型的spring小例子,來看一下它的入口與使用方法:
//建立User類
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//定義XML檔案:user.xml
//省略spring配置檔案頭
......
<bean name="user" class="User">
<property name="name" value="test"/>
</bean>
//使用示例:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("user.xml");
User user = (User)applicationContext.getBean("user");
System.out.println(user.getName());
整個例子非常簡單,就是建立一個User Bean,然後獲得它的name,下面我們從入口
ClassPathXmlApplicationContext開始來了解Spring的啟動流程。
啟動流程
ClassPathXmlApplicationContext構造方法如下:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
//設定xml配置檔案
setConfigLocations(configLocations);
if (refresh) {
//啟動
refresh();
}
}
接下來看啟動核心方法refresh():
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//主要是校驗配置與參數
// Prepare this context for refreshing.
prepareRefresh();
//建立一個BeanFactory,用于建立bean
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//初始化beanFactory, 主要是準備建立bean時需要的環境與關系,并且會建立幾個初始bean
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//允許子類設定postProcessor
//ClassPathXmlApplicationContext是spring基礎的ApplicationContext,是以不需要設定特有功能的postprocessor
//像webApplicationContext則需要把servlet相關的processor設定進來,用來支撐spring mvc相關功能
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//執行個體化processor 并注冊到beanfactory中
//這裡的processor主要是通過AbstractApplicationContext類addBeanFactoryPostProcessor方法設定進來的。
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//執行個體化processor 并注冊到beanfactory中
//這裡processor主要是spring本身自帶的
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//初始化message source并注冊成bean,用于消息解析相關
// Initialize message source for this context.
initMessageSource();
//初始化事件廣播器
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//子類重新整理使用
// Initialize other special beans in specific context subclasses.
onRefresh();
//注冊監聽器,eventMulticaster廣播之前産生的事件
// Check for listener beans and register them.
registerListeners();
//完成beanfactory初始化,確定所有單例bean完成加載,
//主要是通過getBean方法一個一個檢查,為空時就建立bean
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//釋出容器重新整理完成事件,主要内容是定義生命周期的Bean
// Last step: publish corresponding event.
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.
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();
}
}
}
通過中文注釋我們大概了解了spring的啟動流程,因為流程涉及到的方法比較多,是以不一一分析各個方法的源碼了,簡單總結一下流程是這樣的:
1.檢查配置與參數
2.建立一個類型為
ConfigurableListableBeanFactory的beanFactory
3.初始化該beanFactory,主要是配置環境、建立一些預設bean等
4.注冊postprocessor,先擴充類processor後spring基礎類processor
5.注冊廣播與監聽bean
6.完成初始化
7.注冊生命周期管理的bean
其中processor作用是建立bean時允許加入自定義的修改。上面流程中最核心的是第6步,在這一步調用getBean方法,進而真正執行建立bean的工作,接下來我們看一下建立bean的過程。
建立bean
getBean方法最終後調用AbstractBeanFactory的getBean方法,如下:
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
然後執行doGetBean:
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
..................
// Create bean instance.
if (mbd.isSingleton()) {
//從DefaultSingletonBeanRegistry的一級緩存中拿bean,如果不存在執行建立函數
//将建立成功後bean放入到一級緩存中。
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
//bean不存在則建立
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
需要注意的是
DefaultSingletonBeanRegistry有三級緩存,getBean方法隻是從第一級緩存中查找bean的成品。
接下來我們看createBean:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
...............
//執行建立bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
這樣我們就進入了建立bean的核心方法doCreateBean:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
//執行個體化bean
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//執行個體化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
........................
//加入到三級緩存中
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
//為解決依賴問題,需要提前曝光還未建立完成的bean
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
//這裡的日志說得非常清楚,放在第三級緩存中是為了解決循環依賴問題
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//加入到三級緩存中
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
//初始化:主要是設定注入的變量等
// Initialize the bean instance.
Object exposedObject = bean;
try {
//填充屬性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//調用aware類方法,設定beanPostProcessor
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
...............
return exposedObject;
}
這個方法有點長,我把關鍵的幾行挑出來并用中文注釋了,其實思路也挺清晰的,先建立執行個體再初始化最後加入到緩存中。
在doGetBean方法中,會執行getSingleton,這個方法會調用createBean,并将建立的bean加入到一級緩存中,代碼如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
//執行建立bean操作:createBean()方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//加入到一級緩存中
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
加入緩存的代碼如下:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//放入到一級緩存
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
//從三級緩存中删除
this.singletonFactories.remove(beanName);
//從二級緩存中删除
this.earlySingletonObjects.remove(beanName);
//标記該beanname已經被建立過
this.registeredSingletons.add(beanName);
}
}
上面的代碼我們了解到bean的建立過程,總結如下:
getBean-> doGetBean->createBean->doCreateBean->放入一級緩存中->傳回
當然這裡主要是為了了解過程,是以很多細節被忽略了,包括兩個重要功能:aop支援與循環依賴的解決,下一節将着重分析這兩個功能的代碼。
三級緩存與循環依賴
上文有提到
DefaultSingletonBeanRegistry中有三級緩存,用來儲存不同建立階段的bean, 第一級是bean執行個體化後存放的地方,此時還沒有注入依賴關系,第二級則是将第一級緩存的bean進行增強後存放的地方,增強的主要内容是使用動态代理的方式使它支援AOP,最後把第二級的bean注入依賴關系後放入到第三級。
三級緩存如下:
1.第一級為bean成品:singletonObjects
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
2.第二級:earlySingletonObjects
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
3.第三級:singletonFactories
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
那spring是怎麼利用三級緩存來解決依賴問題的呢? 在doCreateBean方法中,spring使用createBeanInstance方法建立了一個bean執行個體,這個執行個體還未進行初始化,它會先放到第三級緩存中,然後檢查依賴關系,下面繼續回到doCreateBean方法中:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
.................................................
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
//這裡的日志說得非常清楚,放在第三級緩存中是為了解決循環依賴問題
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//加入到三級緩存中
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
.........................................
//開始檢查循環依賴
if (earlySingletonExposure) {
//從三級緩存中拿出剛剛執行個體化的bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//拿出它所有依賴的bean
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//如果發現有依賴的bean還沒有被建立就會報異常
if (!actualDependentBeans.isEmpty()) {
//其實看這裡的注釋就知道跟解決循環依賴有關
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
..............................................
}
看完上面代碼你是不是感覺很奇怪,上面代碼隻有檢查依賴關系,那哪裡設定依賴關系呢?下面我們從deCreateBean裡進入populateBean方法中:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
................
//對屬性指派,如果屬性是注入的對象,則會觸發設定依賴關系
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
..................
//解析屬性值,如果屬性是依賴注入
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
................
開始解析引用
public Object resolveValueIfNecessary(Object argName, Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
//通過xml注入的
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//
return resolveReference(argName, ref);
}
//通過autowired注入的
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
................................
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
//調用getBean來建立所依賴的bean
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
}
.....................
從上面的代碼我們可以看出,createBean前會先檢查它所依賴的bean,如果該bean還沒有被建立就調用getBean來建立該bean,這個時候就會有一個問題了,如果兩個bean互相依賴,那豈不是會死循環了?
我們來繼續看看解決循環依賴死循環的關鍵:getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先在一級緩存中找
Object singletonObject = this.singletonObjects.get(beanName);
//如果發現bean還在建立中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從二級緩存中找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//從三級緩存中找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//從三級緩存中移動到二級緩存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
通過代碼我們可以看到即使bean還在三級緩存也會拿出來,這樣它就不會重複執行doCreateBean了。
簡化以上邏輯如下:
- 假設A與B互相依賴
- 建立A時先執行個體化放入三級緩存
- 指派時發現依賴B,調用getBean方法來建立B
- B執行個體化後放入三級緩存
- 指派時發現依賴A,調用getBean方法來建立A
- 這個時候A已經存在于第三緩存了,傳回A給B
- 然後完成B的建立
- 接着完成A的建立。
關注個人微信公衆号:肌肉碼農,回複“好友”讨論問題。