本系列所有基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。由於 Spring 整個體系太過於龐大,因此只會進行關鍵部分的源碼解析。html
什麼是公共註解?公共註解就是常見的Java註解,特別是JSR-250中的註解。例如:@Resource
、@PostConstructor
、@PreDestroy
等等,本文也就主要分析這三個註解在 Spring 中是如何處理的。java
對 @Resource
註解的處理類是 CommonAnnotationBeanPostProcessor
,它經過實現 InstantiationAwareBeanPostProcessor
接口,重寫 postProcessProperties()
方法實現對標註了 @Resource
註解的字段或方法的自動注入。git
InstantiationAwareBeanPostProcessor
接口的詳細信息能夠查看Spring IoC bean 的建立。github
關於 CommonAnnotationBeanPostProcessor
這個後置處理器是怎麼加入到 beanFactory
中的,咱們在 Spring IoC component-scan 節點詳解 一文中介紹過主要是經過 AnnotationConfigUtils#registerAnnotationConfigProcessors()
實現的。spring
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) { // 省略其餘代碼... // 註冊用於處理@Resource、@PostConstructor、@PostDestroy註解的後置處理器 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)); } // 省略其餘代碼... }
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); // 尋找須要注入的字段或方法,並封裝成 InjectionMetadata InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); // 檢查元數據中的註解信息 metadata.checkConfigMembers(beanDefinition); }
上面代碼中的 findAutowiringMetadata()
方法就是利用反射遍歷類的全部字段和方法,找到標註了 @Resource
註解的,並緩存進 injectionMetadataCache
中。緩存
注意:靜態字段和靜態方法會過濾掉。post
findAutowiringMetadata()
方法基本和 AutowiredAnnotationBeanPostProcessor
中的一致,只是處理的註解不一樣而已,能夠查查看Spring IoC @Autowired 註解詳解一文中該方法的詳解。ui
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { // 從injectionMetadataCache緩存中獲取須要注入的字段和方法 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; } // InjectMetadata.java public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 獲取檢查後的元素 Collection<InjectedElement> checkedElements = this.checkedElements; // 若是checkedElements不爲空就使用checkedElements,不然使用injectedElements Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { // 遍歷elementsToIterate for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } // 進行元素注入,見下文詳解 element.inject(target, beanName, pvs); } } }
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { // 若是元素是字段 if (this.isField) { // 強轉成Field類型 Field field = (Field) this.member; // 並設置爲可訪問 ReflectionUtils.makeAccessible(field); // 而後使用反射設置值 field.set(target, getResourceToInject(target, requestingBeanName)); } else { // 檢查是否跳過 if (checkPropertySkipping(pvs)) { return; } try { // 強轉成Method類型 Method method = (Method) this.member; // 並設置爲可訪問 ReflectionUtils.makeAccessible(method); // 使用反射調用方法 method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); }
上面的 lazyLookup
就是是否在屬性或方法上標註了 @Lazy
註解,該註解先暫不討論,因此調用後面的 getResource()
方法。this
protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { // 省略其它代碼... return autowireResource(this.resourceFactory, element, requestingBeanName); } 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(); // 類型匹配(默認爲true) && @Resource註解name屬性不爲空 && 當前beanFactory不包含名稱爲name的bean if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { autowiredBeanNames = new LinkedHashSet<>(); // 按類型查找bean resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); if (resource == null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); } } else { // 按名稱查找bean resource = beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames = Collections.singleton(name); } } // 省略其它代碼... return resource; }
上面 autowireResource()
方法中按類型查找的 resolveDependency()
方法在Spring IoC bean 的建立一文中分析過,按名稱查找 bean
的 resolveBeanByName()
方法實際就是調用 getBean()
經過名稱和類型去獲取 bean
。code
從上面的代碼也能夠看出通常狀況下
@Resource
註解是按名稱注入;而@Autowired
註解時按類型注入,具體能夠查看Spring IoC @Autowired 註解詳解。
處理 @PostConstruct
和 @PreDestroy
註解的處理類是 InitDestroyAnnotationBeanPostProcessor
,CommonAnnotationBeanPostProcessor
繼承與該類,至關於註冊 CommonAnnotationBeanPostProcessor
時也註冊了 InitDestroyAnnotationBeanPostProcessor
。
InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
方法是經過 CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
方法調用的,以下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // 調用InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()方法 super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); // 尋找須要注入的字段或方法,並封裝成 InjectionMetadata InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); // 檢查元數據中的註解信息 metadata.checkConfigMembers(beanDefinition); }
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // 尋找須要標註了@PostConstruct和@PreDestroy註解的方法,並封裝進LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(beanType); // 檢查元數據中的註解信息 metadata.checkConfigMembers(beanDefinition); }
上面代碼中的 findLifecycleMetadata()
方法,就是遍歷當前初始化的 bean
包括其父類中全部標註了 @PostConstruct
和 @PreDestroy
註解的方法,並封裝成 LifecycleMetadata
(該類是 InitDestroyAnnotationBeanPostProcessor
中一個內部類),並放入 lifecycleMetadataCache
緩存中。
這裏咱們簡單看一下 LifecycleMetadata
這個類:
private class LifecycleMetadata { // 目標類,也就是當前正在初始化的bean private final Class<?> targetClass; // 存放標註了@PostConstruct的方法 private final Collection<LifecycleElement> initMethods; // 存放標註了@PreDestroy的方法 private final Collection<LifecycleElement> destroyMethods; // 省略其它代碼... }
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 從lifecycleMetadataCache緩存中獲取LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 反射調用全部初始化方法 metadata.invokeInitMethods(bean, beanName); } // 省略異常處理... return bean; }
看到這裏咱們知道爲何標註了 @PostConstruct
註解的方法比 InitializingBean#afterPropertiesSet()
方法和自定義初始化方法先調用了;由於其在 bean
的初始化前回調就已經調用了,而剩下的兩個是在初始化方法中調用的,詳情能夠查看Spring IoC bean 的初始化一文。
咱們先了解一下 DestructionAwareBeanPostProcessor
,它繼承自 BeanPostProcessor
,以下:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { /** * Bean 銷燬前階段回調 */ void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; /** * bean實例是否要由此方法銷燬 */ default boolean requiresDestruction(Object bean) { return true; } }
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { // 從lifecycleMetadataCache緩存中獲取LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 反射調用全部銷燬方法 metadata.invokeDestroyMethods(bean, beanName); } // 省略異常處理... }
和上面的 @PostConstruct
註解同樣,@PreDestroy
註解標註的方法也比 DisposableBean#destroy()
方法和自定義銷燬方法先調用。
本文主要介紹了 @Resource
、@PostConstruct
、@PreDestroy
註解 Spring 是如何對其處理的,能夠看出 Spring 的註解驅動大多依靠 實現 BeanPostProcessor
及其子類中的 bean
生命週期各個階段的回調方法來進行實現的。
最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。