<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在使用Spring
開發的時候,設定的方式主要有兩種,一種是xml
的方式,另外一種是 java config
的方式。在使用的過程中java config
,我們難免會與註解進行各種打交道,其中,我們使用最多的註解應該就是@Autowired
註解了。這個註解的作用就是注入一個定義好的bean
。
那麼,除了我們常用的屬性注入方式之外,還有哪些方式可以使用這個註解呢?在程式碼層面是如何實現的?
將@Autowired
註解應用於建構函式,如以下範例所示:
@Component public class BeanConfig{ @Autowired private BeanConfig beanConfig; @Autowired public BeanConfig(BeanConfig beanConfig) { this.beanConfig = beanConfig; } }
直接應用於欄位是我們使用最多的方式,但是從程式碼層面使用建構函式注入會更好。因為構造器注入的方式,能夠保證注入的依賴不可變,並確保需要的依賴不為空。此外,構造器注入的依賴總是能夠在返回使用者端(元件)程式碼的時候保證完全初始化的狀態。
此外,還有以下幾種不太常用的方法,見下面的程式碼:
@Autowired private List<BeanConfig> beanConfigList; @Autowired private Set<BeanConfig> beanConfigSet; @Autowired private Map<String, BeanConfig> beanConfigMap;
雖然我們經常使用這個註解,但是我們真的瞭解它的作用嗎?
首先從它的作用域來看,其實這個註解是屬於容器設定的Spring
註解,其他屬於容器設定註解:@Required
, @Primary
, @Qualifier
等。
其次,我們可以直接看字面意思,autowire
,這個詞的意思就是自動裝配的意思。
自動裝配是什麼意思?這個詞的本意是指在一些行業中用機器代替人自動完成一些需要裝配的任務。在Spring
的世界裡,自動組裝是指使用我們需要這個bean
的class
自動組裝Spring
容器中的bean
。
所以這個註解作用的就是自動將Spring
容器中的bean
和我們需要這個bean
一起使用的類組裝起來。
接下來,讓我們看看這個註解背後工作的原理。
Java註解實現的核心技術是反射。讓我們通過一些例子和自己實現一個註解來了解它的工作原理。
我們拿到target
之後就可以用反射給他實現一個邏輯,這種邏輯在這些方法本身的邏輯之外,這讓我們想起proxy、aop等知識,我們相當於為這些方法做了一個邏輯增強。
其實註解的實現主要邏輯大概就是這個思路。總結一下一般步驟如下:
Class
物件。Method
、Field
等類提供了類似getAnnotation
的方法來獲取某個欄位的所有註解。下面我們來實現這個邏輯,程式碼如下:
public void postProcessProperties() throws Exception { Class<BeanConfig> beanConfigClass = BeanConfig.class; BeanConfig instance = beanConfigClass.newInstance(); Field[] fields = beanConfigClass.getDeclaredFields(); for (Field field : fields) { // getAnnotation,判斷是否有Autowired Autowired autowired = field.getDeclaredAnnotation(Autowired.class); if (autowired != null) { String fileName = field.getName(); Class<?> declaringClass = field.getDeclaringClass(); Object bean = new Object(); field.setAccessible(true); field.set(bean, instance); } } }
從上面的實現邏輯不難發現,藉助Java反射,我們可以直接獲取一個類中的所有方法,然後獲取方法上的註解。當然,我們也可以獲取欄位上的註解。在反射的幫助下,我們幾乎可以得到屬於一個類的任何東西。這樣,我們自己簡單做了一個實現。
知道了上面的知識,我們就不難想到,上面的註解雖然簡單,但是@Autowired
和他最大的區別應該只是註解的實現邏輯,其他的如使用反射獲取註解等步驟應該是相同的。
接下來我們看在Spring中,@Autowired
是如何實現的呢?
我們來看@Autowired
在Spring原始碼中是如何定義註解的,如下:
package org.springframework.beans.factory.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required() default true; }
閱讀程式碼可以看出,@Autowired
註解可以應用於五類構造方法,普通方法、引數、欄位、註解,其保留策略是在執行時。
接下來我們看一Spring
對這個註解的邏輯實現。
在Spring
原始碼中,@Autowired
註解位於包中org.springframework.beans.factory.annotation
。經過分析不難發現,Spring對自動裝配註解的實現邏輯位於類:AutowiredAnnotationBeanPostProcessor
。
核心處理程式碼如下:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>(); // 需要處理的目標類 Class<?> targetClass = clazz; do { final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>(); // 通過反射獲取本類的所有欄位,並遍歷每個欄位 // 通過方法findAutowiredAnnotation遍歷每個欄位使用的註解 // 如果用autowired修飾,返回autowired相關屬性 ReflectionUtils.doWithLocalFields(targetClass, field -> { 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; } // 判斷是否指定了required boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); //和上面的邏輯一樣,但是方法是通過反射來處理 ReflectionUtils.doWithLocalMethods(targetClass, method -> { 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.getParameterCount() == 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)); } }); // @Autowired 修飾的註解可能不止一個 // 所以都加入到currElements容器中一起處理 elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
最後,此方法返回一個InjectionMetadata
包含所有autowire
註解的集合。
這個類由兩部分組成:
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) { this.targetClass = targetClass; this.injectedElements = elements; }
一個是我們要處理的目標類,一個是elements
上面方法得到的集合。
有了目標類和所有需要注入的元素,我們就可以實現自動裝配的依賴注入邏輯。實現方法如下。
@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; }
它呼叫的inject
方法就是定義在InjectionMetadata
。
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); } } } /** * Either this or {@link #getResourceToInject} needs to be overridden. */ 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(); } } }
上面程式碼中,方法的引數getResourceToInject
是要注入的名稱,bean這個方法的作用是根據名稱獲取bean
。
以上就是@Autowire
註解實現邏輯的完整解析。
下面是spring容器實現@Autowired
自動注入的時序圖。
本文講解了Spring中最常用的註解之一@Autowired
, 平時我們可能都是使用屬性注入的,但是後續建議大家慢慢改變習慣,使用構造器注入。同時也講解了這個註解背後的實現原理,希望對大家有幫助。
到此這篇關於Spring中最常用的註解之一@Autowired的文章就介紹到這了,更多相關@Autowired註解使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45