Spring 原始碼(九)@Autowired註解實現原理(Spring Bean的自動裝配)
AutowiredAnnotationBeanPostProcessor 類圖
- PriorityOrdered:確認
AutowiredAnnotationBeanPostProcessor
後置處理器的執行優先順序 - BeanFactoryAware:使得
AutowiredAnnotationBeanPostProcessor
可以直接通過BeanFactory
獲取容器中的Bean - BeanPostProcessor:在 Bean 初始化前後執行的後置處理器
- InstantiationAwareBeanPostProcessor:在 Bean 例項化前後和Bean設定屬性值時執行的後置處理器
- SmartInstantiationAwareBeanPostProcessor:智慧例項化Bean的後處理器,如預測Bean的型別和確認Bean的建構函式等。
- MergedBeanDefinitionPostProcessor:合併Bean的定義資訊。
在分析自動裝配前我們先來介紹一下上面的這些後置處理器。
後置處理器介紹
BeanPostProcessor
BeanPostProcessor有兩個方法,postProcessBeforeInitialization
和postProcessAfterInitialization
。它們分別在任何bean初始化回撥之前或之後執行(例如InitializingBean的afterPropertiesSet方法或自定義init-method方法之前或者之後), 在這個時候該bean的屬性值已經填充完成了,並且我們返回的bean例項可能已經是原始例項的包裝型別了。例如返回一個FactoryBean
InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor
繼承自BeanPostProcessor
介面。主要多提供了以下三個方法。
postProcessBeforeInstantiation
該方法是在Bean例項化目標物件之前呼叫,返回的Bean物件可以代理目標,從而有效的阻止了目標Bean的預設例項化。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { // 如果此方法返回一個非null物件,則Bean建立過程將被短路。 // 唯一應用的進一步處理是來自已配置BeanPostProcessors的postProcessAfterInitialization回撥 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; } protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 執行Bean例項化目標物件之前的後置處理方法 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
跟進原始碼我們可以看出,如果此方法返回一個非null物件,則Bean建立過程將被短路。唯一應用的進一步處理是來自已配置BeanPostProcessors的postProcessAfterInitialization回撥。
postProcessAfterInstantiation
該方法執行在通過建構函式或工廠方法在例項化bean之後但在發生Spring屬性填充(通過顯式屬性或自動裝配)之前執行操作。這是在Spring的自動裝配開始之前對給定的bean例項執行自定義欄位注入的理想回調。如果該方法返回false,那麼它會阻斷後續InstantiationAwareBeanPostProcessor
後置處理器的執行,並且會阻止後續屬性填充的執行邏輯。
postProcessPropertyValues
在工廠將給定屬性值應用於給定bean之前,對它們進行後處理。允許檢查是否滿足所有依賴關係,例如基於bean屬性設定器上的“ Required”註解。還允許替換要應用的屬性值,通常是通過基於原始PropertyValues建立新的MutablePropertyValues例項,新增或刪除特定值來實現。
SmartInstantiationAwareBeanPostProcessor
智慧例項化Bean的後處理器,主要提供了三個方法。
predictBeanType
預測從此處理器的postProcessBeforeInstantiation回撥最終返回的bean的型別。
determineCandidateConstructors
確定使用例項化Bean的建構函式。
getEarlyBeanReference
獲取提早暴露的Bean的引用,提早暴露的Bean就是隻完成了例項化,還未完成屬性賦值和初始化的Bean。
MergedBeanDefinitionPostProcessor
postProcessMergedBeanDefinition
合併Bean的定義資訊的後處理方法,該方法是在Bean的例項化之後設定值之前呼叫。
自動裝配的實現
找到需要自動裝配的元素
AutowiredAnnotationBeanPostProcessor
後置處理器主要負責對添加了@Autowired和@Value註解的元素實現自動裝配。所以找到需要自動裝配的元素,其實就是對@Autowired和@Value註解的解析。
AutowiredAnnotationBeanPostProcessor
後置處理器,找出需要自動裝配的元素是在MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition
這個方法中實現的,呼叫鏈路如下:
doWith:445, AutowiredAnnotationBeanPostProcessor$2 (org.springframework.beans.factory.annotation)
doWithLocalFields:657, ReflectionUtils (org.springframework.util)
buildAutowiringMetadata:433, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
findAutowiringMetadata:412, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
postProcessMergedBeanDefinition:235, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
applyMergedBeanDefinitionPostProcessors:1000, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:523, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
從鏈路上我們可以看到,找到需要自動裝配的元素是在findAutowiringMetadata
方法中實現的,該方法會去呼叫buildAutowiringMetadata
方法構建元資料資訊。如果註解被載入屬性上將會被封裝成AutowiredFieldElement
物件;如果註解加在方法上,那麼元素會被封裝成AutowiredMethodElement
物件。這裡兩個物件的inject
方法將最後完成屬性值的注入,主要區別就是使用反射注入值的方式不一樣。原始碼如下:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
// 存放我們找到的元資料資訊
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<InjectionMetadata.InjectedElement>();
// 通過反射找出對應Class物件的所有Field
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 通過反射找到該欄位上所有的註解資訊,並判斷是否有@Autowired和@Value註解,如果有就將該欄位封成AutowiredFieldElement物件
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);、
// 將該欄位封成AutowiredFieldElement物件,並放到快取中
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
// 通過反射找出對應Class物件的所有Method
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 通過反射找到該欄位上所有的註解資訊,並判斷是否有@Autowired和@Value註解,如果有就將該欄位封成AutowiredMethodElement物件
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 將該欄位封成AutowiredMethodElement物件
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
// 迴圈處理父類需要自動裝配的元素
while (targetClass != null && targetClass != Object.class);
// 將需要自動裝配的元素封裝成InjectionMetadata物件,最後合併到Bean定義中
return new InjectionMetadata(clazz, elements);
}
尋找需要自動裝配過程:
- 根據Class物件,通過反射獲取所有的
Field
和```Method````物件 - 通過反射獲取
Field
和Method
上的註解,並判斷是否有@Autowired和@Value註解 - 將註解了@Autowired和@Value的
Field
和Method
封裝成AutowiredFieldElement
和AutowiredMethodElement
物件,等待下一步的自動裝配。 - 迴圈處理父類需要自動裝配的元素
- 將需要自動裝配的元素封裝成InjectionMetadata物件,最後合併到Bean定義的
externallyManagedConfigMembers
屬性中
注入屬性值
AutowiredAnnotationBeanPostProcessor
後置處理器注入屬性值是在postProcessPropertyValues
方法中實現的。原始碼如下:
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
// 獲取需要自動裝配的元資料資訊(這裡實在快取中取)
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
// 呼叫AutowiredFieldElement或AutowiredMethodElement物件的inject方法注入屬性值
element.inject(target, beanName, pvs);
}
}
}
AutowiredFieldElement#inject
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 在容器中獲取需要裝配的Bean
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
...
}
if (value != null) {
// 通過反射設定屬性值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
AutowiredMethodElement#inject
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
}
else {
Class<?>[] paramTypes = method.getParameterTypes();
arguments = new Object[paramTypes.length];
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length);
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
// 在容器中獲取需要裝配的Bean
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
...
}
if (arguments != null) {
try {
// 通過反射呼叫方法設定元素值
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
...
}
}
從這裡的原始碼我們可以看出AutowiredFieldElement
和AutowiredMethodElement
完成自動裝配都是先去容器中找對應的Bean,然後通過反射將獲取到的Bean設定到目標物件中,來完成Bean的自動裝配。
總結
我們可以看出Spring Bean的自動裝配過程就是:
- 根據
Class
物件,通過反射獲取所有的Field
和Method
資訊 - 通反射獲取
Field
和Method
的註解資訊,並根據註解型別,判斷是否需要自動裝配 - 將需要自動裝配的元素,封裝成
AutowiredFieldElement
和AutowiredMethodElement
物件 - 呼叫
AutowiredFieldElement
和AutowiredMethodElement
的inject
方法 - 通過呼叫容器的
getBean()
方法找到需要注入的源資料Bean - 通過反射將找到的源資料Bean注入到目標Bean中
在自動裝配過程中還涉及迴圈依賴的問題,有興趣的可以看下這篇文章Spring 原始碼(八)迴圈依賴
注意:註解注入將在XML注入之前執行;因此,對於通過這兩種方法注入的屬性,XML注入將覆蓋註解注入。