最近在研究Spring bean 生命週期相關知識點以及源碼,因此打算寫一篇 Spring bean生命週期相關的文章,可是整理過程當中發現涉及的點太多並且又很複雜,很難在一篇文章中把Spring bean 的生命週期講清楚,因此最後決定分解成幾個模塊來寫,最後在寫一篇文章把各個內容串聯起來,這樣能夠講的更細更深刻不會猶豫篇幅而講的太籠統。bean 生命週期所涉及的主要流程以下圖所示。程序員
Spring最有名的高級特性非ioc莫屬了,雖然ioc 不是本次要討論的重點,但仍是有必要說一下。對於Spring的ioc我不想過多教科書式的解釋這名次,我也相信每一個使用Spring的程序員都有本身的理解,只是有時很難把本身的理解清楚的解釋給別人而已。下面我說說我本身的理解,有說錯的地方歡迎你們指正。Spring ioc 至少要具有一下兩點功能:面試
準備Bean 整個生命週期須要的數據
這一步是Spring 容器啓動的時候會 定位咱們的配置文件,加載文件,並解析成Bean的定義文件BeanDefinition來爲下一步做準備,這個BeanDefinition會貫穿Spring 啓動初始化的整個流程,很是重要,由於他是數據基礎。算法
管理Bean的整個生命週期spring
有了以上幾個功能以後Spring ioc 就可以控制bean的流程了,這不控制反轉了麼。而咱們只需用註解或者配置文件配置bean的特性以及依賴關係便可。下面說一下有關ApplicationContext 和 BeanDefinition:數組
上述這些功能均可以由Spring容器(好比 ApplicationContext)來實現,Spring啓動時會把全部須要的bean掃描並註冊到容器裏,在這個過程中Spring會根據咱們定義的bean之間的依賴關係來進行注入,依賴關係的維護方式有兩種即XML配置文件或者註解,Spring啓動時會把這些依賴關係轉化成Spring可以識別的數據結構BeanDefinition,並根據它來進行bean的初始化,依賴注入等操做。下面看看一個簡單的Spring容器以下圖: bash
結論:BeanDefinition提供了原材料數據基礎,而ApplicationContext 提供了流程的設計與實現的算法數據結構
咱們須要爲Spring容器提供全部bean的定義以及bean之間的依賴關係,從而進行bean的依賴注入一般有兩種方式,XML配置或者註解,不論是那種最終都會解析成BeanDefinition。app
經過XML配置Bean依賴關係ide
<beans xmlns="http://www.springframework.org/schema/beans">
<!-- orderDao 不須要任何的依賴 -->
<bean id="orderDao" class="spring.DI.OrderDao"/>
<!-- orderService 須要依賴orderDao -->
<bean id="orderService" class="spring.DI.OrderService">
<property name="orderDao" ref="orderDao"/>
</bean>
<!-- orderController orderService 也間接依賴了orderDao -->
<bean id="orderController" class="spring.DI.OrderController">
<property name="orderService" ref="orderService"/>
</bean>
</beans>
複製代碼
public class OrderController {
private OrderService orderService;
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
複製代碼
這種注入方式叫作set 方法注入,只需xml配置 加上對引用的bean的get set方法便可函數
經過註解定義置Bean依賴關係
<context:component-scan base-package="xxx.yyy"/>
複製代碼
@Controller
public class OrderController {
@Autowired
private OrderService orderService;
public OrderController() {
}
}
複製代碼
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
public OrderService() {
}
}
複製代碼
@Repository
public class OrderDao {
public OrderDao() {
}
}
複製代碼
Spring 啓動時會把咱們的定義信息轉化成Spring能看懂的BeanDefinition,而後就能夠由容器來建立bean以及依賴注入了,具體依賴注入的時候對於配置文件和註解的處理手段還不一樣,這個一下子在解釋。
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
複製代碼
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
// 容器初始化入口
refresh();
}
}
複製代碼
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化全部非 懶加載的bean!!!!
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
複製代碼
finishBeanFactoryInitialization(beanFactory);// 初始化全部非 懶加載的bean!!!
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// 此處省略多行與本次無關代碼
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
複製代碼
public void preInstantiateSingletons() throws BeansException {
// 全部beanDefinition集合
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 觸發全部非懶加載單例bean的初始化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 判斷是不是懶加載單例bean,若是是單例的而且不是懶加載的則在Spring 容器
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判斷是不是FactoryBean
if (isFactoryBean(beanName)) {
// 對FactoryBean的處理
}else {
// 若是是普通bean則進行初始化依賴注入,此 getBean(beanName)接下來觸發的邏輯跟
// context.getBean("beanName") 所觸發的邏輯是同樣的
getBean(beanName);
}
}
}
}
複製代碼
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
複製代碼
懶加載的bean 第一次進行getBean的操做調用的也是同一個方法
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
複製代碼
doCreateBean是依賴注入的入口,也是咱們本次要談的核心函數。該方法具體實如今AbstractAutowireCapableBeanFactory類,感興趣的朋友能夠進去看看調用鏈。下面纔剛剛開始進入依賴注入源碼階段。
依賴注入實際上是屬性注入的一種特殊類型,他的特殊之處在於他要注入的是Bean,一樣由Spring管理的Bean,而不是其餘的參數,如String,List,Set,Array這種。
Bean類型的屬性的引用 ref,這種注入屬於依賴注入
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//第一步 建立bean實例 還未進行屬性填充和各類特性的初始化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
Object exposedObject = bean;
try {
// 第二步 進行依賴注入(注入屬性)
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 第三步 執行bean的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}catch (Throwable ex) {
// 拋相應的異常
}
return exposedObject;
}
複製代碼
咱們這裏須要關注的是第二步關於依賴注入這一塊,下面這行代碼
populateBean(beanName, mbd, instanceWrapper);
複製代碼
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 全部的屬性
PropertyValues pvs = mbd.getPropertyValues();
// 這裏是處理自動裝配類型的, autowire=byName 或者byType。若是不配置不走這個分支,xml或註解均可配
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
pvs = newPvs;
}
// 後處理器是否已經準備好(後處理器會處理已@Autowired 形式來注入的bean, 有一個
// 子類AutowiredAnnotationBeanPostProcessor來處理@Autowired注入的bean)
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否須要依賴檢查
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
// 這裏會處理對註解形式的注入 重點!!!!
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
}
// 注入參數的方法(註解的Bean的依賴注入除外)
applyPropertyValues(beanName, mbd, bw, pvs);
}
複製代碼
// 後處理器是否已經準備好(後處理器會處理已@Autowired 形式來注入的bean, 有一個
// 子類AutowiredAnnotationBeanPostProcessor來處理@Autowired注入的bean)
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否須要依賴檢查
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
// 這裏會處理對註解形式的注入,好比 @Autowired註解 由類AutowiredAnnotationBeanPostProcessor來處理
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
}
複製代碼
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
複製代碼
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
// 這裏定義了把誰注入到哪裏
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 進行注入
metadata.inject(bean, beanName, pvs);
}catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
複製代碼
InjectionMetadata在這個類裏頭封裝了依賴的bean與被依賴的bean的信息,好比orderCcontroller 依賴orderService,須要把orderService 注入到orderController。下面貼一下我debug的圖片
protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
複製代碼
applyPropertyValues(beanName, mbd, bw, pvs);
複製代碼
這個步驟主要作的就是把屬性轉換成相對應的類的屬性類型,並最後注入到依賴的bean裏頭,由一下步驟組成:
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// 判斷是否已轉換,已經轉換了則return
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
bw.setPropertyValues(mpvs);
return;
}
original = mpvs.getPropertyValueList();
}
TypeConverter converter = getCustomTypeConverter();
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
// 屬性名 如(name,orderService)
String propertyName = pv.getName();
// 未轉換前的值,稍後貼出debug時的圖
Object originalValue = pv.getValue();
// 轉換後的值,進行轉換處理(重要!!!!)
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
//
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
} else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
} else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
// 轉換完成
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// 這裏就是進行屬性注入的地方,跟上面的inject方法相似
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
複製代碼
下面介紹上述步驟中的兩個核心的流程:
1.進行轉換操做,生成最終須要注入的類型的對象
這個方法會返回一個咱們最終要注入的一個屬性對應類的一個對象
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
複製代碼
根據參數類型作具體的轉換處理,參數類型包括 1.Bean 2.Array 3.List 4.Set 5.Map 6.String 等等。
public Object resolveValueIfNecessary(Object argName, Object value) {
// Bean 類型
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
else if (value instanceof ManagedArray) {
// 處理數組
return resolveManagedArray(argName, (List<?>) value, elementType);
}
else if (value instanceof ManagedList) {
// 處理list
return resolveManagedList(argName, (List<?>) value);
}
else if (value instanceof ManagedSet) {
// 處理set
return resolveManagedSet(argName, (Set<?>) value);
}
else if (value instanceof ManagedMap) {
// 處理map
return resolveManagedMap(argName, (Map<?, ?>) value);
}
else if (value instanceof TypedStringValue) {
// 處理字符串
}
else {
return evaluate(value);
}
}
複製代碼
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("");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}else {
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
}catch (BeansException ex) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName,ex);
}
}
複製代碼
Object bean = this.beanFactory.getBean(refName);
複製代碼
this.beanFactory.getParentBeanFactory().getBean(refName);
複製代碼
從sprig ioc 容器的雙親中獲取bean(被依賴的bean),假如orderCcontroller依賴orderService,則從容器中獲取orderService。這裏有個關鍵點,也就是這個獲取bean的過程也是一個依賴注入的過程,換句話說依賴注入是個遞歸的過程!!!!!!知道被依賴的bean不依賴任何bean。
2.進行注入操做
這一步是經過Java的反射機制根據set 方法把屬性注入到bean裏。
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
複製代碼
protected void setPropertyValue(AbstractNestablePropertyAccessor.PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
if (tokens.keys != null) {
// 處理集合類型
}
else {
// 對非集合類型的處理
AbstractNestablePropertyAccessor.PropertyHandler ph = getLocalPropertyHandler(actualName);
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
}else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}catch (Exception ex) {}
}
valueToApply = convertForProperty(propertyName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 經過反射注入
ph.setValue(object, valueToApply);
}
}
}
複製代碼
public void setValue(final Object object, Object valueToApply) throws Exception {
final Method writeMethod = this.pd.getWriteMethod();
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
writeMethod.setAccessible(true);
return null;
}
});
} else {
writeMethod.setAccessible(true);
}
}
final Object value = valueToApply;
if (System.getSecurityManager() != null) {
} else {
// 經過反射 用set 方法注入屬性
writeMethod.invoke(getWrappedInstance(), value);
}
}
複製代碼
本文主要寫了一下幾點:
1.依賴注入這個步驟是整個Spring ioc 的一部分以及一個功能
2.依賴注入是屬性注入的一種,區別在於這個屬性是由Spring管理的bean
3.觸發依賴注入的時機
4.兩種依賴注入方式 配置文件以及註解
5.源碼部分
歡迎你們提出改進點,小弟入行不久功力淺。
參考:
《Spring 技術內幕》 《Spring 源碼深度剖析》
其餘文章