該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 Spring 原始碼分析 GitHub 地址 進行閱讀
Spring 版本:5.1.14.RELEASE
開始閱讀這一系列文章之前,建議先檢視《深入瞭解 Spring IoC(面試題)》這一篇文章
該系列其他文章請檢視:《死磕 Spring 之 IoC 篇 - 文章導讀》
@Autowired 等註解的實現原理
在上一篇《Bean 的屬性填充階段》文章中講到,在建立一個 Bean 的例項物件後,會對這個 Bean 進行屬性填充。在屬性填充的過程中,獲取到已定義的屬性值,然後會通過 InstantiationAwareBeanPostProcessor 對該屬性值進行處理,最後通過反射機制將屬性值設定到這個 Bean 中。在 Spring 內部有以下兩個 InstantiationAwareBeanPostProcessor 處理器:
- AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 註解標註的屬性,獲取對應屬性值
- CommonAnnotationBeanPostProcessor,會解析 @Resource 註解標註的屬性,獲取對應的屬性值
本文將會分析這兩個處理器的實現,以及涉及到的相關物件
這兩個處理器在哪被註冊?
在前面的《解析自定義標籤(XML 檔案)》 和 《BeanDefinition 的解析過程(面向註解)》文章中可以知道,在 XML 檔案中的 <context:component-scan />
標籤的處理過程中,會底層藉助於 ClassPathBeanDefinitionScanner
掃描器,去掃描指定路徑下符合條件(@Component 註解)的 BeanDefinition 們,關於 @ComponentScan 註解的解析也是藉助於這個掃描器實現的。掃描過程如下:
// ClassPathBeanDefinitionScanner.java
public int scan(String... basePackages) {
// <1> 獲取掃描前的 BeanDefinition 數量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
// <2> 進行掃描,將過濾出來的所有的 .class 檔案生成對應的 BeanDefinition 並註冊
doScan(basePackages);
// Register annotation config processors, if necessary.
// <3> 如果 `includeAnnotationConfig` 為 `true`(預設),則註冊幾個關於註解的 PostProcessor 處理器(關鍵)
// 在其他地方也會註冊,內部會進行判斷,已註冊的處理器不會再註冊
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
// <4> 返回本次掃描註冊的 BeanDefinition 數量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
在第 <3>
步會呼叫 AnnotationConfigUtils 的 registerAnnotationConfigProcessors(BeanDefinitionRegistry)
方法,如下:
// AnnotationConfigUtils.java
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
/**
* Register all relevant annotation post processors in the given registry.
* @param registry the registry to operate on
* @param source the configuration source element (already extracted)
* that this registration was triggered from. May be {@code null}.
* @return a Set of BeanDefinitionHolders, containing all bean definitions
* that have actually been registered by this call
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 處理 Spring 應用上下文中的配置類
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 處理 @Autowired 以及 @Value 註解
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// (條件啟用)處理 JSR-250 註解 @Resource,如 @PostConstruct、@PreDestroy 等
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Processor 物件(條件啟用)處理 JPA 註解場景
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 處理標註 @EventListener 的 Spring 事件監聽方法
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
// 用於 @EventListener 標註的事件監聽方法構建成 ApplicationListener 物件
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
在這個方法中可以看到會註冊 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 兩個處理器,然後在 Spring 應用上下文重新整理階段會將其初始化並新增至 AbstractBeanFactory 的 beanPostProcessors
集合中,那麼接下來我們先來分析這兩個處理器
回顧 Bean 的建立過程
第一步:回到《Bean 的建立過程》文章中的“對 RootBeanDefinition 加工處理”小節,會呼叫這個方法:
// AbstractAutowireCapableBeanFactory.java
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
呼叫所有 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法對 RootBeanDefinition 進行加工處理,例如:
- AutowiredAnnotationBeanPostProcessor,會先解析出
@Autowired
和@Value
註解標註的屬性的注入元資訊,後續進行依賴注入 - CommonAnnotationBeanPostProcessor,會先解析出
@Resource
註解標註的屬性的注入元資訊,後續進行依賴注入,它也會找到@PostConstruct
和@PreDestroy
註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬
第二步:回到《Bean 的建立過程》文章中的“屬性填充”小節,該過程會進行下面的處理:
// <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// <5.1> 遍歷所有的 BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果為 InstantiationAwareBeanPostProcessor 型別
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// <5.2> 呼叫處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行後置處理
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要相容老版本
if (pvsToUse == null) {
// <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// <5.3.2> 呼叫處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行後置處理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
// <5.3.3> 如果處理後的 PropertyValues 物件為空,直接 `return`,則不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
if (pvsToUse == null) {
return;
}
}
// <5.4> 將處理後的 `pvsToUse` 複製給 `pvs`
pvs = pvsToUse;
}
}
}
這裡不會呼叫所有 InstantiationAwareBeanPostProcessor 的 postProcessProperties 方法對 pvs
(MutablePropertyValues)屬性值物件進行處理,例如:
- AutowiredAnnotationBeanPostProcessor,會根據前面解析出來的
@Autowired
和@Value
註解標註的屬性的注入元資訊,進行依賴注入 - CommonAnnotationBeanPostProcessor,會根據前面解析出來的
@Resource
註解標註的屬性的注入元資訊,進行依賴注入
可以看到@Autowired
、@Value
和 @Resource
註解的實現就是基於這兩個處理器實現的,接下來我們來看看這兩個處理器的具體實現
AutowiredAnnotationBeanPostProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
,主要處理 @Autowired
和 @Value
註解進行依賴注入
體系結構
可以看到 AutowiredAnnotationBeanPostProcessor 實現了 MergedBeanDefinitionPostProcessor 和 InstantiationAwareBeanPostProcessor 兩個介面
構造方法
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
/**
* 儲存需要處理的註解
*/
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
private String requiredParameterName = "required";
private boolean requiredParameterValue = true;
private int order = Ordered.LOWEST_PRECEDENCE - 2;
@Nullable
private ConfigurableListableBeanFactory beanFactory;
private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
/**
* 快取需要注入的欄位元資訊
*/
private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
/**
* Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
* standard {@link Autowired @Autowired} annotation.
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available.
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
}
可以看到會新增 @Autowired
和 @Value
兩個註解,如果存在 JSR-330 的 javax.inject.Inject
註解,也是支援的
postProcessMergedBeanDefinition 方法
postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
方法,找到 @Autowired
和 @Value
註解標註的欄位(或方法)的元資訊,如下:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 找到這個 Bean 所有需要注入的屬性(@Autowired 或者 @Value 註解)
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
直接呼叫 findAutowiringMetadata(...)
方法獲取這個 Bean 的注入元資訊物件
1. findAutowiringMetadata 方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
// 生成一個快取 Key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 先嚐試從快取中獲取
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) { // 是否需要重新整理,也就是判斷快取是否命中
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) { // 加鎖,再判斷一次
if (metadata != null) {
metadata.clear(pvs);
}
// 構建一個需要注入的元資訊物件
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
首先嚐試從快取中獲取這個 Bean 對應的注入元資訊物件,沒有找到的話則呼叫 buildAutowiringMetadata(final Class<?> clazz)
構建一個,然後再放入快取中
2. buildAutowiringMetadata 方法
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
// <1> 建立 `currElements` 集合,用於儲存 @Autowired、@Value 註解標註的欄位
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// <2> 遍歷這個 Class 物件的所有欄位
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// <2.1> 找到該欄位的 @Autowired 或者 @Value 註解,返回 `ann` 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
// <2.2> 進行過濾,static 修飾的欄位不進行注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// <2.3> 獲取註解中的 `required` 配置
boolean required = determineRequiredStatus(ann);
// <2.4> 根據該欄位和 `required` 構建一個 AutowiredFieldElement 物件,新增至 `currElements`
currElements.add(new AutowiredFieldElement(field, required));
}
});
// <3> 遍歷這個 Class 物件的所有方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// <3.1> 嘗試找到這個方法的橋接方法,沒有的話就是本身這個方法
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
// <3.2> 如果是橋接方法則直接跳過
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// <3.3> 找到該方法的 @Autowired 或者 @Value 註解,返回 `ann` 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// <3.4> 進行過濾,static 修飾的方法不進行注入
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
// <3.5> 獲取註解中的 `required` 配置
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// <3.6> 構建一個 AutowiredMethodElement 物件,新增至 `currElements`
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
// <4> 找到父類,迴圈遍歷
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// <5> 根據從這個 Bean 解析出來的所有 InjectedElement 物件生成一個 InjectionMetadata 注入元資訊物件,並返回
return new InjectionMetadata(clazz, elements);
}
過程如下:
- 建立
currElements
集合,用於儲存@Autowired
、@Value
註解標註的欄位 - 遍歷這個 Class 物件的所有欄位
- 找到該欄位的
@Autowired
或者@Value
註解,返回ann
物件,沒有的話返回空物件,則直接跳過不進行下面的操作 - 進行過濾,static 修飾的欄位不進行注入
- 獲取註解中的
required
配置 - 根據該欄位和
required
構建一個 AutowiredFieldElement 物件,新增至currElements
- 找到該欄位的
- 遍歷這個 Class 物件的所有方法
- 嘗試找到這個方法的橋接方法,沒有的話就是本身這個方法
- 如果是橋接方法則直接跳過
- 找到該方法的
@Autowired
或者@Value
註解,返回ann
物件,沒有的話返回空物件,則直接跳過不進行下面的操作 - 進行過濾,static 修飾的方法不進行注入
- 獲取註解中的
required
配置 - 構建一個 AutowiredMethodElement 物件,新增至
currElements
- 找到父類,迴圈遍歷
- 根據從這個 Bean 解析出來的所有 InjectedElement 物件生成一個 InjectionMetadata 注入元資訊物件,並返回
整個過程很簡單,就是解析出所有 @Autowired
或者 @Value
註解標註的方法或者欄位,然後構建一個 InjectionMetadata 注入元資訊物件
postProcessProperties 方法
postProcessProperties(PropertyValues pvs, Object bean, String beanName)
方法,根據 @Autowired
和 @Value
註解標註的欄位(或方法)的元資訊進行依賴注入,如下:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找到這個 Bean 的注入元資訊物件
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 進行注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
先找到這個 Bean 的注入元資訊物件,上面已經講過了,然後呼叫其 inject(...)
方法,這裡先來看到 InjectionMetadata
這個物件
InjectionMetadata 注入元資訊物件
org.springframework.beans.factory.annotation.InjectionMetadata
,某個 Bean 的注入元資訊物件
public class InjectionMetadata {
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
private final Class<?> targetClass;
/**
* 需要注入的欄位(或方法)的元資訊
*/
private final Collection<InjectedElement> injectedElements;
@Nullable
private volatile Set<InjectedElement> checkedElements;
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
this.targetClass = targetClass;
this.injectedElements = elements;
}
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
}
可以看到注入方法非常簡單,就是遍歷所有的 InjectedElement 物件,呼叫他們的 inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)
方法
AutowiredFieldElement
AutowiredAnnotationBeanPostProcessor 的私有內部類,注入欄位物件,如下:
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
/** 是否必須 */
private final boolean required;
/** 是否快取起來了 */
private volatile boolean cached = false;
/** 快取的物件 */
@Nullable
private volatile Object cachedFieldValue;
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// <1> 獲取 `field` 欄位
Field field = (Field) this.member;
Object value;
// <2> 如果進行快取了,則嘗試從快取中獲取
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
// <3> 否則,開始進行解析
else {
// <3.1> 建立一個依賴注入描述器 `desc`
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
/**
* <3.2> 通過 {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency} 方法
* 找到這個欄位對應的 Bean(們)
*/
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// <3.3> 和快取相關,如果有必要則將本次找到的注入物件快取起來,避免下次再進行解析
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
// <4> 如果獲取到該欄位對應的物件,則進行屬性賦值(依賴注入)
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
直接看到 inject(...)
方法,注入的過程如下:
- 獲取
field
欄位 - 如果進行快取了,則嘗試從快取中獲取
- 否則,開始進行解析
- 建立一個依賴注入描述器
desc
- 【核心】通過
DefaultListableBeanFactory#resolveDependency(...)
方法,找到這個欄位對應的 Bean(們) - 和快取相關,如果有必要則將本次找到的注入物件快取起來,避免下次再進行解析
- 建立一個依賴注入描述器
- 如果獲取到該欄位對應的物件,則進行屬性賦值(依賴注入),底層就是通過反射機制為該欄位賦值
可以看到整個的核心在於通過 DefaultListableBeanFactory#resolveDependency(...)
方法找到欄位對應的 Bean,這裡也許是一個集合物件,所以也可能找到的是多個 Bean,該方法在後面進行分析
AutowiredMethodElement
AutowiredAnnotationBeanPostProcessor 的私有內部類,注入方法物件,如下:
private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
/** 是否必須 */
private final boolean required;
/** 是否快取起來了 */
private volatile boolean cached = false;
/** 快取的方法引數物件 */
@Nullable
private volatile Object[] cachedMethodArguments;
public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
super(method, pd);
this.required = required;
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (checkPropertySkipping(pvs)) {
return;
}
// <1> 獲取 `method` 方法
Method method = (Method) this.member;
// <2> 如果進行快取了,則嘗試從快取中獲取方法引數物件
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
}
// <3> 否則,開始進行解析
else {
// <3.1> 獲取方法的引數型別集合 `paramTypes`,根據引數位置確定引數
Class<?>[] paramTypes = method.getParameterTypes();
arguments = new Object[paramTypes.length];
// <3.2> 構建一個依賴注入描述器陣列 `descriptors`,用於儲存後續建立的物件
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
Set<String> autowiredBeans = new LinkedHashSet<>(paramTypes.length);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
// <3.3> 根據引數順序遍歷該方法的引數
for (int i = 0; i < arguments.length; i++) {
// <3.3.1> 為第 `i` 個方法引數建立一個 MethodParameter 物件
MethodParameter methodParam = new MethodParameter(method, i);
// <3.3.2> 建立依賴描述器 `currDesc`,並新增至 `descriptors` 陣列
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
/**
* <3.3.3> 通過 {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency} 方法
* 找到這個方法引數對應的 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);
}
}
// <3.4> 和快取相關,如果有必要則將本次找到的方法引數物件快取起來,避免下次再進行解析
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
Object[] cachedMethodArguments = new Object[paramTypes.length];
System.arraycopy(descriptors, 0, cachedMethodArguments, 0, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == paramTypes.length) {
Iterator<String> it = autowiredBeans.iterator();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
// <4> 如果找到該方法的引數(們),則進行屬性賦值(依賴注入)
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
// 通過反射機制呼叫該方法
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}
直接看到 inject(...)
方法,注入的過程如下:
- 獲取
method
方法 - 如果進行快取了,則嘗試從快取中獲取方法引數物件
- 否則,開始進行解析
- 獲取方法的引數型別集合
paramTypes
,根據引數位置確定引數 - 構建一個依賴注入描述器陣列
descriptors
,用於儲存後續建立的物件 - 根據引數順序遍歷該方法的引數
- 為第
i
個方法引數建立一個 MethodParameter 物件 - 建立依賴描述器
currDesc
,並新增至descriptors
陣列 - 【核心】通過
DefaultListableBeanFactory#resolveDependency(...)
方法,找到這個方法引數對應的 Bean(們) - 和快取相關,如果有必要則將本次找到的方法引數物件快取起來,避免下次再進行解析
- 為第
- 獲取方法的引數型別集合
- 如果找到該方法的引數(們),則進行屬性賦值(依賴注入),底層就是通過反射機制呼叫該方法
可以看到整個的核心也是通過 DefaultListableBeanFactory#resolveDependency(...)
方法找到方法引數對應的 Bean,該方法在後面進行分析
CommonAnnotationBeanPostProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
,主要處理 @Resource
註解進行依賴注入,以及 @PostConstruct
和 @PreDestroy
生命週期註解的處理
體系結構
可以看到 CommonAnnotationBeanPostProcessor 實現了 MergedBeanDefinitionPostProcessor 和 InstantiationAwareBeanPostProcessor 兩個介面,還實現了 DestructionAwareBeanPostProcessor 介面,用於生命週期中的初始化和銷燬的處理
構造方法
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
@Nullable
private static Class<? extends Annotation> webServiceRefClass;
@Nullable
private static Class<? extends Annotation> ejbRefClass;
static {
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
webServiceRefClass = clazz;
}
catch (ClassNotFoundException ex) {
webServiceRefClass = null;
}
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
ejbRefClass = clazz;
}
catch (ClassNotFoundException ex) {
ejbRefClass = null;
}
}
/**
* Create a new CommonAnnotationBeanPostProcessor,
* with the init and destroy annotation types set to
* {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
* respectively.
*/
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
}
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
protected transient Log logger = LogFactory.getLog(getClass());
/**
* 初始化註解,預設為 @PostConstruct
*/
@Nullable
private Class<? extends Annotation> initAnnotationType;
/**
* 銷燬註解,預設為 @PreDestroy
*/
@Nullable
private Class<? extends Annotation> destroyAnnotationType;
private int order = Ordered.LOWEST_PRECEDENCE;
@Nullable
private final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
}
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
this.destroyAnnotationType = destroyAnnotationType;
}
}
可以看到會設定初始化註解為 @PostConstruct
,銷燬註解為 @PreDestroy
,這兩個註解都是 JSR-250 註解;另外如果存在 javax.xml.ws.WebServiceRef
和 javax.ejb.EJB
註解也是會進行設定的
postProcessMergedBeanDefinition 方法
postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
方法,找到 @PostConstruct
和 @PreDestroy
註解標註的方法,並構建 LifecycleMetadata 物件,找到 @Resource
註解標註的欄位(或方法)的元資訊,如下:
// CommonAnnotationBeanPostProcessor.java
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 先呼叫父類的方法,找到 @PostConstruct 和 @PreDestroy 註解標註的方法,並構建 LifecycleMetadata 物件
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 找到 @Resource 註解標註的欄位(或方法),構建一個 InjectionMetadata 物件,用於後續的屬性注入
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
整個的過程原理和 AutowiredAnnotationBeanPostProcessor 差不多,先從快取中獲取,未命中則呼叫對應的方法進行構建,下面先來看看父類中的方法
buildLifecycleMetadata 方法
// InitDestroyAnnotationBeanPostProcessor.java
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
整個過程比較簡單,找到這個 Bean 中 @PostConstruct
和 @PreDestroy
註解標註的方法,然後構建一個 LifecycleMetadata 生命週期元資訊物件
buildResourceMetadata 方法
// CommonAnnotationBeanPostProcessor.java
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
整個過程也比較簡單,解析出這個 Bean 帶有 @Resource
註解的所有欄位(或方法),構建成對應的 ResourceElement 物件,然後再構建成一個 InjectionMetadata 注入元資訊物件
postProcessProperties 方法
postProcessProperties(PropertyValues pvs, Object bean, String beanName)
方法,根據 @Resource
註解標註的欄位(或方法)的元資訊進行依賴注入,如下:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
// 進行注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
先找到這個 Bean 的注入元資訊物件,上面已經講過了,然後呼叫其 inject(...)
方法,該物件上面已經講過了,實際就是呼叫其內部 InjectedElement 的 inject(...)
方法
postProcessBeforeInitialization 方法
初始化 Bean 的時候會先執行 @PostConstruct
標註的初始化方法
// InitDestroyAnnotationBeanPostProcessor.java
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 找到 @PostConstruct 和 @PreDestroy 註解標註的方法們所對應的 LifecycleMetadata 物件
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 執行 @PostConstruct 標註的初始化方法
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
// InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
for (LifecycleElement element : initMethodsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}
postProcessBeforeDestruction 方法
銷燬 Bean 的時候先執行 @PreDestroy
註解標註的銷燬方法
// InitDestroyAnnotationBeanPostProcessor.java
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
// 找到 @PostConstruct 和 @PreDestroy 註解標註的方法們所對應的 LifecycleMetadata 物件
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 執行 @PreDestroy 標註的銷燬方法
metadata.invokeDestroyMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
}
catch (Throwable ex) {
logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
}
}
// InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;
Collection<LifecycleElement> destroyMethodsToUse =
(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
if (!destroyMethodsToUse.isEmpty()) {
for (LifecycleElement element : destroyMethodsToUse) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}
ResourceElement
CommonAnnotationBeanPostProcessor 的私有內部類,@Resource 注入欄位(或方法)物件
構造方法
protected abstract class LookupElement extends InjectionMetadata.InjectedElement {
/** Bean 的名稱 */
protected String name = "";
/** 是否為預設的名稱(通過註解定義的) */
protected boolean isDefaultName = false;
/** Bean 的型別 */
protected Class<?> lookupType = Object.class;
@Nullable
protected String mappedName;
public LookupElement(Member member, @Nullable PropertyDescriptor pd) {
super(member, pd);
}
public final DependencyDescriptor getDependencyDescriptor() {
if (this.isField) {
return new LookupDependencyDescriptor((Field) this.member, this.lookupType);
}
else {
return new LookupDependencyDescriptor((Method) this.member, this.lookupType);
}
}
}
private class ResourceElement extends LookupElement {
/** 是否延遲載入 */
private final boolean lazyLookup;
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
Resource resource = ae.getAnnotation(Resource.class);
String resourceName = resource.name();
Class<?> resourceType = resource.type();
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) {
resourceName = this.member.getName();
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
else if (embeddedValueResolver != null) {
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
if (Object.class != resourceType) {
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
this.name = (resourceName != null ? resourceName : "");
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
}
ResourceElement 的構造方法會通過 @Resource
註解和該欄位(或方法)解析出基本資訊
可以看到還繼承了 InjectionMetadata 的靜態內部類 InjectedElement,我們先來看到這個類的 inject(...)
方法
inject 方法
public abstract static class InjectedElement {
protected final Member member;
protected final boolean isField;
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable 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();
}
}
}
@Nullable
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return null;
}
}
不管是欄位還是方法,底層都是通過反射機制進行賦值或者呼叫,都會呼叫 getResourceToInject(...)
方法獲取到欄位值或者方法引數
getResourceToInject 方法
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
如果是延遲載入,則呼叫 buildLazyResourceProxy(...)
方法返回一個代理物件,如下:
protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) {
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return element.lookupType;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
return getResource(element, requestingBeanName);
}
@Override
public void releaseTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
if (element.lookupType.isInterface()) {
pf.addInterface(element.lookupType);
}
ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);
return pf.getProxy(classLoader);
}
否則,呼叫 getResource(...)
方法獲取注入物件
getResource 方法
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
if (StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
if (this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
}
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
前面的判斷忽略掉,直接看到最後會呼叫 autowireResource(...)
方法,並返回注入資訊
autowireResource 方法
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
else {
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
@Resource
註解相比於 @Autowired
註解的處理更加複雜點,不過我們這裡可以看到也會呼叫 DefaultListableBeanFactory#resolveDependency(...)
方法,找到對應的注入物件,該方法在後面進行分析
1. resolveDependency 處理依賴方法
resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, TypeConverter typeConverter)
方法,找到對應的依賴 Bean,該方法在《Bean 的建立過程》中也提到了,獲取 Bean 的例項物件時,構造器注入的引數也是通過該方法獲取的,本文的依賴注入底層也是通過該方法實現的,這裡我們對該方法一探究竟
// DefaultListableBeanFactory.java
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// <1> 設定引數名稱探測器,例如通過它獲取方法引數的名稱
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// <2> 如果依賴型別為 Optional 型別
if (Optional.class == descriptor.getDependencyType()) {
// 呼叫 `createOptionalDependency(...)` 方法,先將 `descriptor` 注入表述器封裝成 NestedDependencyDescriptor 物件
// 底層處理和下面的 `5.2` 相同
return createOptionalDependency(descriptor, requestingBeanName);
}
// <3> 否則,如果依賴型別為 ObjectFactory 或 ObjectProvider 型別
else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) {
// 返回一個 DependencyObjectProvider 私有內部類物件,並沒有獲取到例項的 Bean,需要呼叫其 getObject() 方法獲取目標物件
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// <4> 否則,如果依賴型別為 javax.inject.Provider 型別
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
// 返回一個 Jsr330Provider 私有內部類物件,該物件也繼承 DependencyObjectProvider
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
// <5> 否則,通用的處理邏輯
else {
// <5.1> 先通過 AutowireCandidateResolver 嘗試獲取一個代理物件,延遲依賴注入則會返回一個代理物件
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
// <5.2> 如果上面沒有返回代理物件,則進行處理,呼叫 `doResolveDependency(...)` 方法
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
過程如下:
- 設定引數名稱探測器,例如通過它獲取方法引數的名稱
- 如果依賴型別為 Optional 型別,則呼叫
createOptionalDependency(...)
方法,先將descriptor
注入表述器封裝成 NestedDependencyDescriptor 物件,底層處理和下面的5.2
相同 - 否則,如果依賴型別為 ObjectFactory 或 ObjectProvider 型別,直接返回一個
DependencyObjectProvider
私有內部類物件,並沒有獲取到例項的 Bean,需要呼叫其 getObject() 方法獲取目標物件 - 否則,如果依賴型別為 javax.inject.Provider 型別,直接返回一個
Jsr330Provider
私有內部類物件,該物件也繼承 DependencyObjectProvider - 否則,通用的處理邏輯
- 先通過 AutowireCandidateResolver 嘗試獲取一個代理物件,延遲依賴注入則會返回一個代理物件
- 如果上面沒有返回代理物件,則進行處理,呼叫
doResolveDependency(...)
方法
我們需要關注的是上面的第 5.2
步所呼叫 doResolveDependency(...)
方法,這一步是底層實現
2. doResolveDependency 底層處理依賴方法
// DefaultListableBeanFactory.java
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 設定當前執行緒的注入點,並返回上次的注入點,屬於巢狀注入的一個保護點
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// <1> 針對給定的工廠給定一個快捷實現的方式,暫時忽略
// 例如考慮一些預先解析的資訊,在進入所有 Bean 的常規型別匹配演算法之前,解析演算法將首先嚐試通過此方法解析快捷方式
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
// 返回快捷的解析資訊
return shortcut;
}
// 依賴的型別
Class<?> type = descriptor.getDependencyType();
// <2> 獲取註解中的 value 對應的值,例如 @Value、@Qualifier 註解配置的 value 屬性值,注意 @Autowired 沒有 value 屬性配置
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// <2.1> 解析註解中的 value,因為可能是佔位符,需要獲取到相應的資料
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// <2.2> 進行型別轉換,並返回
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// <3> 解析複合的依賴物件(Array、Collection、Map 型別),獲取該屬性元素型別的 Bean 們
// 底層和第 `4` 原理一樣,這裡會將 `descriptor` 封裝成 MultiElementDescriptor 型別
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// <4> 查詢與型別相匹配的 Bean 們
// 返回結果:key -> beanName;value -> 對應的 Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// <5> 如果一個都沒找到
if (matchingBeans.isEmpty()) {
// <5.1> 如果 @Autowired 配置的 required 為 true,表示必須,則丟擲異常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
// <5.2> 否則,返回一個空物件
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// <6> 如果匹配的 Bean 有多個,則需要找出最優先的那個
if (matchingBeans.size() > 1) {
// <6.1> 找到最匹配的那個 Bean,通過 @Primary 或者 @Priority 來決定,或者通過名稱決定
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// <6.2> 如果沒有找到最匹配的 Bean,則丟擲 NoUniqueBeanDefinitionException 異常
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
// <6.3> 獲取到最匹配的 Bean,傳值引用給 `instanceCandidate`
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
// <7> 否則,只有一個 Bean,則直接使用其作為最匹配的 Bean
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// <8> 將依賴注入的 Bean 的名稱新增至方法入參 `autowiredBeanNames` 集合,裡面儲存依賴注入的 beanName
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// <9> 如果匹配的 Bean 是 Class 物件,則根據其 beanName 依賴查詢到對應的 Bean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
// <10> 返回依賴注入的 Bean
return result;
}
finally {
// 設定當前執行緒的注入點為上一次的注入點,因為本次注入結束了
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
依賴處理的過程稍微有點複雜,如下:
-
針對給定的工廠給定一個快捷實現的方式,暫時忽略
例如考慮一些預先解析的資訊,在進入所有 Bean 的常規型別匹配演算法之前,解析演算法將首先嚐試通過此方法解析快捷方式
-
獲取註解中的 value 對應的值,例如
@Value
、@Qualifier
註解配置的 value 屬性值,注意 @Autowired 沒有 value 屬性配置- 解析註解中的 value,因為可能是佔位符,需要獲取到相應的資料
- 進行型別轉換,並返回
-
解析複合的依賴物件(Array、Collection、Map 型別),獲取該屬性元素型別的 Bean 們,呼叫
resolveMultipleBeans(...)
方法底層和下面第
4
步原理一樣,這裡會將descriptor
封裝成 MultiElementDescriptor 型別,如果找到了則直接返回 -
查詢與型別相匹配的 Bean 們,呼叫
findAutowireCandidates(...)
方法返回結果:key -> beanName;value -> 對應的 Bean
-
如果一個都沒找到
- 如果
@Autowired
配置的 required 為 true,表示必須,則丟擲異常 - 否則,返回一個空物件
- 如果
-
如果匹配的 Bean 有多個,則需要找出最優先的那個
- 找到最匹配的那個 Bean,通過
@Primary
或者@Priority
來決定,或者通過名稱決定,呼叫determineAutowireCandidate(...)
方法 - 如果沒有找到最匹配的 Bean,則丟擲 NoUniqueBeanDefinitionException 異常
- 獲取到最匹配的 Bean,傳值引用給
instanceCandidate
- 找到最匹配的那個 Bean,通過
-
否則,只有一個 Bean,則直接使用其作為最匹配的 Bean
-
將依賴注入的 Bean 的名稱新增至方法入參
autowiredBeanNames
集合,裡面儲存依賴注入的 beanName -
如果匹配的 Bean 是 Class 物件,則根據其 beanName 依賴查詢到對應的 Bean
-
返回依賴注入的 Bean
關於上面第 3
步對於符合依賴物件的處理這裡不做詳細分析,因為底層和第 4
步一樣,接下來分析上面第 4
、6
步所呼叫的方法
findAutowireCandidates 方法
findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor)
方法,找到符合條件的依賴注入的 Bean 們,如下:
// DefaultListableBeanFactory.java
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// <1> 從當前上下文找到該型別的 Bean 們(根據型別)
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
// <2> 定義一個 Map 物件 `result`,用於儲存符合條件的 Bean
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
/**
* <3> 遍歷 Spring 內部已處理的依賴物件集合,可以跳到 AbstractApplicationContext#prepareBeanFactory 方法中看看
* 會有一下幾個內建處理物件:
* BeanFactory 型別 -> 返回 DefaultListableBeanFactory
* ResourceLoader、ApplicationEventPublisher、ApplicationContext 型別 -> 返回 ApplicationContext 物件
*/
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// <4> 遍歷第 `1` 步找到的 Bean 的名稱們
for (String candidate : candidateNames) {
// <4.1> 如果滿足下面兩個條件,則新增至 `result` 集合中
if (!isSelfReference(beanName, candidate) // 如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
&& isAutowireCandidate(candidate, descriptor)) { // 符合注入的條件
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// <5> 如果沒有找到符合條件的 Bean,則再嘗試獲取
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
// <5.1> 再次遍歷第 `1` 步找到的 Bean 的名稱們
for (String candidate : candidateNames) {
// <5.2> 如果滿足下面三個條件,則新增至 `result` 集合中
if (!isSelfReference(beanName, candidate) // 如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
&& isAutowireCandidate(candidate, fallbackDescriptor) // 符合注入的條件
&& (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) { // 不是複合型別,或者有 @Qualifier 註解
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// <6> 如果還沒有找到符合條件的 Bean,則再嘗試獲取
// 和上面第 `5` 步的區別在於必須是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate)
&& (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate))
&& isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
// <7> 返回 `result`,符合條件的 Bean
return result;
}
過程大致如下:
-
從當前上下文找到該型別的 Bean 們(根據型別)
-
定義一個 Map 物件
result
,用於儲存符合條件的 Bean -
遍歷 Spring 內部已處理的依賴物件集合,例如你依賴注入 BeanFactory 型別的物件,則拿到的是 DefaultListableBeanFactory 物件,依賴注入 ResourceLoader、ApplicationEventPublisher、ApplicationContext 型別的物件, 拿到的就是當前 Spring 上下文 ApplicationContext 物件
-
遍歷第
1
步找到的 Bean 的名稱們-
如果滿足下面兩個條件,則新增至
result
集合中如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)、符合注入的條件
-
-
如果沒有找到符合條件的 Bean,則再嘗試獲取
-
再次遍歷第
1
步找到的 Bean 的名稱們 -
如果滿足下面三個條件,則新增至
result
集合中如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)、符合注入的條件、不是複合型別,或者有
@Qualifier
註解
-
-
如果還沒有找到符合條件的 Bean,則再嘗試獲取,和上面第
5
步的區別在於必須是自引用(這個 Bean 是在需要依賴它的 Bean 的內部定義的) -
返回
result
,符合條件的 Bean
總結下來:從當前上下文找到所有該型別的依賴注入物件然後返回,注意,如果你依賴注入的物件就是本身這個 Bean 內部定義的物件有特殊處理。
例如注入一個集合物件,元素型別的 Bean 有一個是定義在本身這個 Bean 的內部,如果僅有這個 Bean 則會注入進行;如果除了本身這個 Bean 內部定義了,其他地方也定義了,那麼本身這個 Bean 內部定義的 Bean 是不會被注入的;因為是自引用的 Bean 不會優先考慮,除非一個都沒找到,才會嘗試獲取自引用的 Bean
determineAutowireCandidate 方法
determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor)
方法,找到最匹配的那個依賴注入物件,如下:
@Nullable
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
// <1> 嘗試獲取一個 @Primary 註解標註的 Bean,如果有找到多個則會丟擲異常
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
// <2> 如果第 `1` 步找到了則直接返回
if (primaryCandidate != null) {
return primaryCandidate;
}
// <3> 嘗試找到 @Priority 註解優先順序最高的那個 Bean,如果存在相同的優先順序則會丟擲異常
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
// <4> 如果第 `3` 步找到了則直接返回
if (priorityCandidate != null) {
return priorityCandidate;
}
// Fallback
// <5> 兜底方法,遍歷所有的 Bean
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
// <5.1> 如果滿足下面其中一個條件則直接返回
if ((beanInstance != null
&& this.resolvableDependencies.containsValue(beanInstance)) // 該 Bean 為 Spring 內部可處理的 Bean,例如 ApplicationContext
|| matchesBeanName(candidateName, descriptor.getDependencyName())) { // 名稱相匹配
return candidateName;
}
}
// <6> 上面都沒選出來則返回一個空物件
return null;
}
如果找到了多個匹配的依賴注入物件,則需要找到最匹配的那個 Bean,過程大致如下:
- 嘗試獲取一個
@Primary
註解標註的 Bean,如果有找到多個則會丟擲異常 - 如果第
1
步找到了則直接返回 - 嘗試找到
@Priority
註解優先順序最高的那個 Bean,如果存在相同的優先順序則會丟擲異常 - 如果第
3
步找到了則直接返回 - 兜底方法,遍歷所有的 Bean
- 如果滿足下面其中一個條件則直接返回:該 Bean 為 Spring 內部可處理的 Bean(例如 ApplicationContext、BeanFactory)、名稱相匹配
- 上面都沒選出來則返回一個空物件
總結
本文講述了 @Autowired
、@Value
和 @Resource
等註解的實現原理,在《Bean 的建立過程》中我們可以瞭解到,在 Spring Bean 生命週期的很多階段都可以通過相應的 BeanPostProcessor 處理器進行擴充套件,其中《Bean 的屬性填充階段》會通過 InstantiationAwareBeanPostProcessor
對 Bean 進行處理,有以下兩個處理器:
- AutowiredAnnotationBeanPostProcessor,主要處理
@Autowired
和@Value
註解進行依賴注入 - CommonAnnotationBeanPostProcessor,主要處理
@Resource
註解進行依賴注入,以及@PostConstruct
和@PreDestroy
生命週期註解的處理
原理就是找到註解標註的欄位(或方法),建立對應的注入元資訊物件,然後根據該元資訊物件進行注入(反射機制),底層都是通過 DefaultListableBeanFactory#resolveDependency
方法實現的,找到符合條件的 Bean(根據型別),然後篩選出最匹配的那個依賴注入物件。
疑問:@Bean 等註解的實現原理又是怎樣的呢?別急,在後續文章進行分析