偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

都用過(guò)@Autowired,但你知道它是怎么實(shí)現(xiàn)的嗎?

開(kāi)發(fā)
本文講解了Spring中最常用的注解之一@Autowired, 平時(shí)我們可能都是使用屬性注入的,但是后續(xù)建議大家慢慢改變習(xí)慣,使用構(gòu)造器注入。同時(shí)也講解了這個(gè)注解背后的實(shí)現(xiàn)原理,希望對(duì)大家有幫助。

?前言

在使用Spring?開(kāi)發(fā)的時(shí)候,配置的方式主要有兩種,一種是xml?的方式,另外一種是 java config?的方式。在使用的過(guò)程中java config?,我們難免會(huì)與注解進(jìn)行各種打交道,其中,我們使用最多的注解應(yīng)該就是@Autowired?注解了。這個(gè)注解的作用就是注入一個(gè)定義好的bean。

那么,除了我們常用的屬性注入方式之外,還有哪些方式可以使用這個(gè)注解呢?在代碼層面是如何實(shí)現(xiàn)的?

如何使用@Autowired注解?

將@Autowired注解應(yīng)用于構(gòu)造函數(shù),如以下示例所示:

@Component
public class BeanConfig{
@Autowired
private BeanConfig beanConfig;

@Autowired
public BeanConfig(BeanConfig beanConfig){
this.beanConfig = beanConfig;
}
}

直接應(yīng)用于字段是我們使用最多的方式,但是從代碼層面使用構(gòu)造函數(shù)注入會(huì)更好。因?yàn)闃?gòu)造器注入的方式,能夠保證注入的依賴不可變,并確保需要的依賴不為空。此外,構(gòu)造器注入的依賴總是能夠在返回客戶端(組件)代碼的時(shí)候保證完全初始化的狀態(tài)。

此外,還有以下幾種不太常用的方法,見(jiàn)下面的代碼:

 @Autowired
private List<BeanConfig> beanConfigList;

@Autowired
private Set<BeanConfig> beanConfigSet;

@Autowired
private Map<String, BeanConfig> beanConfigMap;

雖然我們經(jīng)常使用這個(gè)注解,但是我們真的了解它的作用嗎?

首先從它的作用域來(lái)看,其實(shí)這個(gè)注解是屬于容器配置的Spring?注解,其他屬于容器配置注解:@Required?, @Primary?, @Qualifier等。

其次,我們可以直接看字面意思,autowire,這個(gè)詞的意思就是自動(dòng)裝配的意思。

自動(dòng)裝配是什么意思?這個(gè)詞的本意是指在一些行業(yè)中用機(jī)器代替人自動(dòng)完成一些需要裝配的任務(wù)。在Spring?的世界里,自動(dòng)組裝是指使用我們需要這個(gè)bean的class?自動(dòng)組裝Spring?容器中的bean。

所以這個(gè)注解作用的就是自動(dòng)將Spring?容器中的bean?和我們需要這個(gè)bean一起使用的類組裝起來(lái)。

接下來(lái),讓我們看看這個(gè)注解背后工作的原理。

如何實(shí)現(xiàn)@Autowired 注解?

Java注解實(shí)現(xiàn)的核心技術(shù)是反射。讓我們通過(guò)一些例子和自己實(shí)現(xiàn)一個(gè)注解來(lái)了解它的工作原理。

我們拿到target之后就可以用反射給他實(shí)現(xiàn)一個(gè)邏輯,這種邏輯在這些方法本身的邏輯之外,這讓我們想起proxy、aop等知識(shí),我們相當(dāng)于為這些方法做了一個(gè)邏輯增強(qiáng)。

其實(shí)注解的實(shí)現(xiàn)主要邏輯大概就是這個(gè)思路。總結(jié)一下一般步驟如下:

  1. 使用反射機(jī)制獲取類的Class對(duì)象。
  2. 通過(guò)這個(gè)類對(duì)象,可以得到它的每一個(gè)方法方法,或者字段等。
  3. Method、Field等類提供了類似getAnnotation的方法來(lái)獲取某個(gè)字段的所有注解。
  4. 拿到注解后,我們可以判斷該注解是否是我們要實(shí)現(xiàn)的注解,如果是,則實(shí)現(xiàn)注解邏輯。

下面我們來(lái)實(shí)現(xiàn)這個(gè)邏輯,代碼如下:

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);
}
}
}

從上面的實(shí)現(xiàn)邏輯不難發(fā)現(xiàn),借助Java反射,我們可以直接獲取一個(gè)類中的所有方法,然后獲取方法上的注解。當(dāng)然,我們也可以獲取字段上的注解。在反射的幫助下,我們幾乎可以得到屬于一個(gè)類的任何東西。這樣,我們自己簡(jiǎn)單做了一個(gè)實(shí)現(xiàn)。

知道了上面的知識(shí),我們就不難想到,上面的注解雖然簡(jiǎn)單,但是@Autowired和他最大的區(qū)別應(yīng)該只是注解的實(shí)現(xiàn)邏輯,其他的如使用反射獲取注解等步驟應(yīng)該是相同的。

接下來(lái)我們看在Spring中,@Autowired是如何實(shí)現(xiàn)的呢?

Spring中源碼解析

我們來(lái)看@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注解可以應(yīng)用于五類構(gòu)造方法,普通方法、參數(shù)、字段、注解,其保留策略是在運(yùn)行時(shí)。

接下來(lái)我們看一Spring對(duì)這個(gè)注解的邏輯實(shí)現(xiàn)。

在Spring?源碼中,@Autowired?注解位于包中org.springframework.beans.factory.annotation?。經(jīng)過(guò)分析不難發(fā)現(xiàn),Spring對(duì)自動(dòng)裝配注解的實(shí)現(xiàn)邏輯位于類:AutowiredAnnotationBeanPostProcessor。

核心處理代碼如下:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz){
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
// 需要處理的目標(biāo)類
Class<?> targetClass = clazz;

do {
final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();

// 通過(guò)反射獲取本類的所有字段,并遍歷每個(gè)字段
// 通過(guò)方法findAutowiredAnnotation遍歷每個(gè)字段使用的注解
// 如果用autowired修飾,返回autowired相關(guān)屬性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
// 檢查靜態(tài)方法上是否使用了自動(dòng)裝配注解
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));
}
});
//和上面的邏輯一樣,但是方法是通過(guò)反射來(lái)處理
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 修飾的注解可能不止一個(gè)
// 所以都加入到currElements容器中一起處理
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);

return new InjectionMetadata(clazz, elements);
}

最后,此方法返回一個(gè)InjectionMetadata?包含所有autowire注解的集合。

這個(gè)類由兩部分組成:

public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements){
this.targetClass = targetClass;
this.injectedElements = elements;
}

一個(gè)是我們要處理的目標(biāo)類,一個(gè)是elements上面方法得到的集合。

有了目標(biāo)類和所有需要注入的元素,我們就可以實(shí)現(xiàn)自動(dòng)裝配的依賴注入邏輯。實(shí)現(xiàn)方法如下。

@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;
}

它調(diào)用的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();
}
}
}

上面代碼中,方法的參數(shù)getResourceToInject?是要注入的名稱,bean這個(gè)方法的作用是根據(jù)名稱獲取bean。

以上就是@Autowire注解實(shí)現(xiàn)邏輯的完整解析。

下面是spring容器實(shí)現(xiàn)@Autowired自動(dòng)注入的時(shí)序圖。

圖片

總結(jié)

本文講解了Spring中最常用的注解之一@Autowired, 平時(shí)我們可能都是使用屬性注入的,但是后續(xù)建議大家慢慢改變習(xí)慣,使用構(gòu)造器注入。同時(shí)也講解了這個(gè)注解背后的實(shí)現(xiàn)原理,希望對(duì)大家有幫助。

責(zé)任編輯:武曉燕 來(lái)源: JAVA旭陽(yáng)
相關(guān)推薦

2023-01-13 16:53:17

Annotation底層元注解

2020-08-16 10:58:20

Pandaspython開(kāi)發(fā)

2023-11-22 07:42:01

2022-10-14 18:19:41

YouTube

2021-08-05 18:21:29

Autowired代碼spring

2024-11-08 09:37:10

C#組件庫(kù)

2012-05-08 08:55:56

2018-01-25 21:32:24

Emoji表情iPhone

2024-11-07 12:33:47

2020-06-03 16:50:09

Node.js框架開(kāi)發(fā)

2020-01-07 10:55:37

并發(fā)Nginx運(yùn)維

2020-07-06 12:09:24

DNS域名系統(tǒng)IP地址

2010-11-23 10:21:53

跳槽

2023-12-22 16:39:47

Java函數(shù)式接口開(kāi)發(fā)

2019-07-03 14:34:39

Docker云計(jì)算技術(shù)

2024-11-26 00:45:29

free區(qū)域字段

2022-08-02 10:01:34

Import語(yǔ)句ES模塊

2020-06-05 08:37:08

Object.entr開(kāi)發(fā)Object.from

2018-07-09 15:32:57

2020-08-23 09:18:30

Pandas函數(shù)數(shù)據(jù)分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)