Spring-Framework 原始碼閱讀之@Autowired和AutowiredAnnotationBeanPostProcessor
今天接下去講我們的內容,上次的解析了AnnotationBeanUtils這個類的運用和原始碼。今天主要關注的是Autowired和 AutowiredAnnotationBeanPostProcessor這2個類。首先我們來看一下Autowired標籤的定義。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documentedpublic @interface Autowired { /** * * <p>Defaults to {@code true}. */ boolean required() default true; }
從標籤的定義和上面的註釋可以知道,該標籤可以用於建構函式、方法、引數、標籤上。為了使這個標籤生效,我們需要一個解析這個標籤的類,Spring 為我們提供解析的類就是AutowiredAnnotationBeanPostProcessor,這是個BeanPostProcessor類。關於BeanPostProcessor大家可以查閱相關資料,之後等我讀到這個介面的時候,會具體的和大家一起探討。這裡我們以引數注入為例,來分析了一下,這個類到底做了哪些事情。這個引數注入主要是它的一個內部類AutowiredFieldElement來處理。
而這個類的inject()方法被呼叫是在AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法上。
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { 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; }
從這裡我們知道 findAutowiringMetadata()方法這裡獲取注入元資料資訊,然後呼叫InjectionMetadata.inject()的方法。在以引數注入就是呼叫AutowiredFieldElement.inject()方法。
這些型別的關係,將在之後解釋。讓我們具體來看一下 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 { //通過BeanFactory的resolveDependency()方法解決依賴的值。也就是這個引數需要注入的值 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } 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)) { if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) {//這裡就是通過反射設定引數可見性,然後把值設定到該引數上。 ReflectionUtils.makeAccessible(field); field.set(bean, value); } }
接下來,我們需要知道,AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues()方法什麼時候被呼叫。在這個函式上,我們關注2個引數,一個是PropertyDescriptor
型別的陣列,一個beanName。beanName就是我們例項化的物件,其中PropertyDescriptor就是描述這個名為beanName的Bean的引數內容。在AbstractAutowireCapableBeanFactory的
doCreateBean()方法裡,有一個populateBean()裡面呼叫了postProcessPropertyValues()。從方法名稱上,我們知道建立Bean(doCreateBean)>填充Bean(populateBean)。在這個populateBean()裡面有如一下這麼一段程式碼:
if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } }
在for迴圈裡面,判斷每一個BeanPostProcessor ,看這個BeanPostProcessor 是否實現InstantiationAwareBeanPostProcessor這個介面,剛好,我們知道AutowiredAnnotationBeanPostProcessors實現了這個介面,過載了InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法。到此為止,我們知道Bean的Autowired的注入實現。那麼我們在回到postProcessPropertyValues的findAutowiringMetadata(),從上面已經點出這個方法是找出注入元資料資訊。那麼它是如何查詢的,看如下程式碼:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. 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); } try { metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } catch (NoClassDefFoundError err) { throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + "] for autowiring metadata: could not find class that it depends on", err); } } } } return metadata; }
其中的關鍵程式碼就是InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);這句話。從這裡我們知道他是從this.injectionMetadataCache,這是一個Map,key為beanName,value為注入元資料InjectionMetadata。即直接從這個Map中獲取,那麼接下來我們就要知道這個注入資訊是什麼時候放入到這個快取Map上的。從上面程式碼上,我們看到
this.injectionMetadataCache.put(cacheKey, metadata);這段程式碼,這程式碼就是把注入資訊放到this.injectionMetadataCache上。那麼,從這裡我們可以猜測,findAutowiringMetadata()這個方法肯定被呼叫了多次,在Bean例項化過程中。從檢視程式碼,印證了我的想法。
再回到AutowiredAnnotationBeanPostProcessor的BeanPostProcessor,之前我們知道他實現InstantiationAwareBeanPostProcessor這個介面。在這裡,我要說AutowiredAnnotationBeanPostProcessor還實現了MergedBeanDefinitionPostProcessor這個介面,這個MergedBeanDefinitionPostProcessor介面只有一個函式postProcessMergedBeanDefinition(),該方法就是用來整合BeanDefinition。讓我們自己毛估估也知道,這個對Bean內部的引數描述PropertyDescriptor也應該在專門用來整合Bean定義的這種BeanPostProcessors。從 AutowiredAnnotationBeanPostProcessor的如下程式碼,它果然實現postProcessMergedBeanDefinition函式。在其中呼叫了findAutowiringMetadata()。
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { if (beanType != null) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } }
第一次呼叫findAutowiringMetadata()的時候,我們this.injectionMetadataCache.get()得到metadata為null,這樣就會進入if{}段程式碼,接著 呼叫 buildAutowiringMetadata()從該Bean的位元組碼中得到注入元資訊。接著我們把得到的注入源資訊InjectionMetadata放到this.injectionMetadataCache上。那麼我們看一下這個方法。
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>(); ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { 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); currElements.add(new AutowiredFieldElement(field, required)); } } }); 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; } 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); currElements.add(new AutowiredMethodElement(method, required, pd)); } } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
從上面,我們知道這個方法主要通過ReflectionUtils.doWithLocalFields()和ReflectionUtils.doWithLocalMethods()來得到源注入資訊。到這裡,我們可以大致知道依賴注入了。瞎 main提供一下test,大家可以通過debug知道Bean的建立流程。
@Test public void testResourceInjection2() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); bpp.setBeanFactory(bf); bf.addBeanPostProcessor(bpp); RootBeanDefinition bd1 = new RootBeanDefinition(Uss.class); bd1.setScope(RootBeanDefinition.SCOPE_SINGLETON); bf.registerBeanDefinition("uss", bd1); RootBeanDefinition bd2 = new RootBeanDefinition(Tss.class); bd2.setScope(RootBeanDefinition.SCOPE_SINGLETON); bf.registerBeanDefinition("tss", bd2); Uss uss = (Uss) bf.getBean("uss"); Tss tss = (Tss) bf.getBean("tss"); System.out.println(uss.getTss() == tss); System.out.println(tss.getUss() == uss); }
public class Uss { private String id; @Autowired private Tss tss; public String getId() { return id; } public void setId(String id) { this.id = id; } public Tss getTss() { return tss; } public void setTss(Tss tss) { this.tss = tss; } }
public class Tss { private String id; @Autowired private Uss uss; public String getId() { return id; } public void setId(String id) { this.id = id; } public Uss getUss() { return uss; } public void setUss(Uss uss) { this.uss = uss; } }
在這裡,還有一些東西沒有講的非常的清楚,第一,是我自己有些程式碼還不太清楚,整體把握不住,還有些要等到我看到了其他內容在和大家一起分享。
相關推薦
Spring-Framework 原始碼閱讀之@Autowired和AutowiredAnnotationBeanPostProcessor
今天接下去講我們的內容,上次的解析了AnnotationBeanUtils這個類的運用和原始碼。今天主要關注的是Autowired和 AutowiredAnnotationBeanPostProcessor這2個類。首先我們來看一下Autowired標籤的定義。 @Target({ElementType
Spring-Framework 原始碼閱讀之AnnotationBeanUtils
Java程式設計師,就是要學會一個名字叫做“春”的東西,這玩意運用的非常的廣泛,現在如果你的業務系統或者軟體沒有在這個東西上開發,都不要意思拿出來。因為你更不上時代了。在平時的工作的中基本都是簡單的運用,沒有深入的瞭解內部的肌理。這次我一定可以滿滿的看完裡面的骨架。加油!加油!加油! 在之前我也看過一
Spring Ioc 原始碼分析之Bean的載入和構造
我們都知道,Spring Ioc和Aop是Spring的核心的功能,因此花一點時間去研究還是很有意義的,如果僅僅是知其所以然,也就體會不到大師設計Spring的精華,還記得那句話,Spring為JavaEE開發帶來了春天。IOC就是Inversion of control 也就是控制反轉的意思,另一種稱呼叫做
Spring和Spring Boot2.0原始碼閱讀環境搭建和結構
一:Spring 第一步:安裝git和gradle,以及Java8,並配置環境變數。 第二步:開啟gitbash,cd到你要放置spring原始碼工程的目錄,輸入:git clone https://github.com/spring-projects/sprin
Spring原始碼閱讀之Bean載入(xml)1
先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactory是bean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了
Spring原始碼學習之BeanFactory和FactoryBean
今天在學習Spring原始碼的時候,發現了spring中不僅僅有BeanFactory,還有FactoryBean,突然覺得分不清這兩者之間有什麼不同,難道僅僅是名字嗎?但是從名字上我們也能看出一些端
Robot Framework 原始碼閱讀筆記 之二
上次走到了具體測試執行的地方,感覺缺乏一個全域性觀,有點走不下去。 還是再回頭看看整個設計思路,所有的模組文件都可以從這裡訪問到: 使用文件: http://robotframework.org/robotframework/ 介面文件: http://robot-fra
Spring 原始碼閱讀之 深入理解 finishBeanFactoryInitialization
原始碼入口 上篇博文中我們看到了將Spring環境中的 BeanPostProcessor找出來,新增到BeanFactory中的beanPostProcessors中,統一維護,本片博文繼續往下拓展,看下Spring如何例項化bean,以及如何實現在bean的例項化通過各種各樣的後置處理器完成bean的增強
Netty原始碼閱讀之如何將TCP的讀寫操作和指定執行緒繫結
**原文連結**:[http://xueliang.org/article/detail/20200712234015993](http://xueliang.org/article/detail/20200712234015993) # 前言 在Netty的執行緒模型中,對於一個TCP連線的讀寫操作,都是
Spring源碼閱讀之Springs-beans(一)容器的基本實現
beans 閱讀 gin com -i add wid ans lock 一、Spring-beans Spring源碼閱讀之Springs-beans(一)容器的基本實現
Promise原始碼閱讀之建構函式+then過程
前言 Promise是非同步程式設計的一種方案,ES6規範中將其寫入規範標準中,統一了用法。 考慮到瀏覽器的相容性,Vue專案中使用promise,就具體閱讀promise原始碼,看看內部的具體實現。 具體分析 通過具體例項來閱讀promise原始碼的實現,例項如下: new
Spring-web原始碼解析之Filter-OncePerRequestFilter
轉自: http://blog.csdn.net/ktlifeng/article/details/50630934 基於4.1.7.RELEASE 我們先看一個filter-mapping的配置
Netty 原始碼閱讀之初始環境搭建
推薦 netty 系列原始碼解析合集 http://www.iocoder.cn/Netty/Netty-collection/?aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3R6c18xMDQxMjE4MTI5L2FydGljbGUvZGV0YWlscy83OD
jdk原始碼閱讀之——arraylist
首先看一下他的建構函式: public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 其實arraylist還有其他的建構函式,可以指定陣列的長度,這裡先從最基本的入
netty原始碼閱讀之效能優化工具類之Recycle異執行緒獲取物件
在這篇《netty原始碼閱讀之效能優化工具類之Recycler獲取物件》文章裡面,我們還有一個scavenge()方法沒有解析,也就是在別的執行緒裡面回收物件。下面我們開始介紹,從這個方法開始進入: boolean scavenge() { // con
STL原始碼剖析之map和set
之前分析二叉搜尋樹和平衡二叉樹時,真心感覺樹的實現真是難,特別是平衡二叉樹,不平衡之後需要調整,還要考慮各種情況,累感不愛.今天看到這個紅黑樹,發現比平衡二叉樹還難,但是紅黑樹比平衡二叉樹使用的場景更多,所以平常使用時,我們需要了解紅黑樹的實現原理,如果有能力,可以自己實現,但是如果實在做不出來,也
Spring文件閱讀之AOP
Aspect-oriented Programming (AOP) 補充了Object-oriented Programming (OOP)。OOP最重要的概念模組是類(class),而AOP中則是切面。AOP可以在多種型別和多個類間進行操作,可以認為AOP串起了這些資料。OOP使用封裝,繼承和多型來定義物件
我的原始碼閱讀之路:redux原始碼剖析
前言 用過react的小夥伴對redux其實並不陌生,基本大多數的React應用用到它。一般大家用redux的時候基本都不會單獨去使用它,而是配合react-redux一起去使用。剛學習redux的時候很容易弄混淆redux和react-redux,以為他倆是同一個
netty原始碼閱讀之解碼值基於固定長度解碼器分析
固定長度解碼器FixedLengthFrameDecoder比較簡單,我們看下它類的註釋: /** * A decoder that splits the received {@link ByteBuf}s by the fixed number * of bytes.
netty原始碼閱讀之解碼之基於長度域解碼器引數分析
這篇文章我們放鬆一點,只分析基於長度域解碼器的幾個引數, lengthFieldOffset :長度域的偏移量,也就是長度域要從什麼地方開始 lengthFieldLength:長度域的長度,也就是長度域佔多少個位元組 lengthAdjustment:長度域的值的調整