您好,登錄后才能下訂單哦!
Spring在單值注入時如何按類型查找匹配的Bean,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
我經常寫如下代碼:
@Autowired private AService aservice;
不知你是否也好奇,Spring是如何找到AService類型的Bean的呢?,我們就聊聊這個->單值注入時如何按類型查找匹配的Bean.
很簡單,核心就3步。
Spring在DefaultListableBeanFactory.findAutowireCandidates方法中實現。 其部分源碼如下:
String[] candidateNames = BeanFactoryUtils .beanNamesForTypeIncludingAncestors ( this, requiredType, true, descriptor.isEager());
這個beanNamesForTypeIncludingAncestors的作用就是,獲取requiredType(AService)類型所有匹配的beanName(包含先祖BeanFactory)。
beanNamesForTypeIncludingAncestors內部是如果實現的呢?我概括了下簡要邏輯如下:
遍歷所有的BeanDefinition,獲得所有的BeanName.
針對所有的BeanName,先嘗試獲取單例進行匹配,若未匹配上再以Bean Definition進行匹配。
匹配時,如果Bean是FactoryBean,先嘗試FactoryBean生產的實際Bean進行匹配,若未匹配上再以FactoryBean 進行匹配。
DefaultListableBeanFactory.determinePrimaryCandidate實現了篩選首選Bean的邏輯, 其中的核心方法是isPrimary,該方法是判斷當前Bean是否是首選Bean的。源碼如下:
protected boolean isPrimary(String beanName, Object beanInstance) { if (containsBeanDefinition(beanName)) { return getMergedLocalBeanDefinition(beanName).isPrimary(); } BeanFactory parent = getParentBeanFactory(); return (parent instanceof DefaultListableBeanFactory && ((DefaultListableBeanFactory) parent).isPrimary(beanName,beanInstance)); }
getMergedLocalBeanDefinition(beanName).isPrimary()方法,對應AbstractBeanDefinition的primary屬性,該屬性被賦值的地方是在AnnotatedBeanDefinitionReader.doRegisterBean方法中。有如下邏輯。
//省略甚多代碼...... for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } //省略很多代碼....
看到這,我們可以得出一個結論:
被@Primary注解的bean,單值注入時會作為首選。
Spring是如何確定Bean的優先級的呢?
在DefaultListableBeanFactory.determineHighestPriorityCandidate中,實現按優先級選擇Bean 其中,獲取Bean的優先級的邏輯在getPriority方法中,如下:
protected Integer getPriority(Object beanInstance) { Comparator<Object> comparator = getDependencyComparator(); if (comparator instanceof OrderComparator) { return ((OrderComparator) comparator).getPriority(beanInstance); } return null; }
查看OrderComparator的實現類AnnotationAwareOrderComparator中的源碼發現, 獲取優先級的邏輯實際在在OrderUtils.getPriority 中
public static Integer getPriority(Class<?> type) { if (priorityAnnotationType == null) { return null; } Object cached = priorityCache.get(type); if (cached != null) { return (cached instanceof Integer ? (Integer) cached : null); } Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType); Integer result = null; if (priority != null) { result = (Integer) AnnotationUtils.getValue(priority); } priorityCache.put(type, (result != null ? result : NOT_ANNOTATED)); return result; }
在OrderUtils 向上查找發現 priorityAnnotationType的值為:
priorityAnnotationType = (Class<? extends Annotation>) ClassUtils.forName("javax.annotation.Priority", OrderUtils.class.getClassLoader());
被@Priority注解的類,其值越小,在單值注入時,越優先選擇。
Spring的源碼非常多,僅有這3步當然是不行的,我準備了流程圖,梳理了Spring單值注入時查找匹配Bean的流程。
看完上述內容,你們掌握Spring在單值注入時如何按類型查找匹配的Bean的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。