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