返回顶部
首页 > 资讯 > 精选 >Java的@Autowired原理是什么
  • 219
分享到

Java的@Autowired原理是什么

2023-07-02 12:07:35 219人浏览 薄情痞子
摘要

本篇内容主要讲解“Java的@Autowired原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java的@Autowired原理是什么”吧!@Autowired使用构造函数注入publ

本篇内容主要讲解“Java的@Autowired原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java的@Autowired原理是什么”吧!

@Autowired使用

构造函数注入

public Class Outer { private Inner inner; @Autowired public Outer(Inner inner) {  this.inner = inner; }}

属性注入

public Class Outer { @Autowired private Inner inner;}

方法注入

public Class Outer { private Inner inner; public Inner getInner() {  return inner; } @Autowired public void setInner(Inner inner) {  this.inner = inner; }}

目前绝大部分的代码都使用第2、第3种。第1种在bean实例化时完成,而第2、第3种的实现原理都是一样的,在属性填充时完成。本篇将介绍第二第三种的是实现原理

在开始之前,如果我们自己设计@Autowired,我们应该怎么实现?我想做法还是比较简单的

  • 通过反射查找bean的class下所有注解了@Autowired的字段和方法

  • 获取到字段,通过getBean(字段)获取到对应bean,然后再通过反射调用field的set将bean注入

@Autowired源码分析

AutowiredAnnotationBeanPostProcessor

该类是@Autowired的具体实现类,先预览一下类方法

Java的@Autowired原理是什么

发现实际有机会介入bean的创建操作只有可能是后置处理器,用于后置处理的有3个方法,其中一个过时不用,分别是postProceSSMergedBeanDefinitionpostProcessProperties后置处理,我们再看一下这2个方法的具体代码

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter  implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { ... @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {  // 1. 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型  InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);  metadata.checkConfigMembers(beanDefinition); } ... @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {  // 1. 寻找通过@Autowired注解的属性或者方法  InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);  try {   // 2. 注入   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; } ...}

跟我们的猜想是一样的,首先先找出所有注解了@Autowired的属性或者方法,然后进行注入,当然postProcessMergedBeanDefinition后置处理器的调用肯定是在postProcessProperties之前的,这里我们回顾一下spring bean的创建过程。

2个处理器我已用黄色标出

Java的@Autowired原理是什么

1.查找所有@Autowired

// 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {  // Fall back to class name as cache key, for backwards compatibility with custom callers.  // 获取缓存的key值,一般以beanName做key  String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());  // Quick check on the concurrent map first, with minimal locking.  // 从缓存中获取metadata  InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);  // 检测metadata是否需要更新  if (InjectionMetadata.needsRefresh(metadata, clazz)) {   synchronized (this.injectionMetadataCache) {    metadata = this.injectionMetadataCache.get(cacheKey);    if (InjectionMetadata.needsRefresh(metadata, clazz)) {     if (metadata != null) {      metadata.clear(pvs);     }     // 通过clazz类,查找所有@Autowired的属性或者方法,并封装成InjectionMetadata类型     metadata = buildAutowiringMetadata(clazz);     // 将metadata加入缓存     this.injectionMetadataCache.put(cacheKey, metadata);    }   }  }  return metadata; }

可以看到spring依然在用缓存的方式提高性能,继续跟踪核心代码buildAutowiringMetadata(clazz)

 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {  // 查看clazz是否有Autowired注解  if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {   return InjectionMetadata.EMPTY;  }  // 这里需要注意AutowiredFieldElement,AutowiredMethodElement均继承了InjectionMetadata.InjectedElement  // 因此这个列表是可以保存注解的属性和被注解的方法的  List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();  Class<?> targetClass = clazz;  // 1. 通过do while循环,递归的往直接继承的父类寻找@Autowired  do {   final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();   // 2. 通过反射,获取所有属性,doWithLocalFields则是循环的对每个属性应用以下匿名方法   ReflectionUtils.doWithLocalFields(targetClass, field -> {    // 判断当前field属性是否含有@Autowired的注解    MergedAnnotation<?> ann = findAutowiredAnnotation(field);    if (ann != null) {     // 返回该属性在类中的修饰符,如果等于static常量,则抛出异常,@Autowired不允许注解在静态属性上     if (Modifier.isStatic(field.getModifiers())) {      if (logger.isInfoEnabled()) {       logger.info("Autowired annotation is not supported on static fields: " + field);      }      return;     }     // @Autowired有required属性,获取required的值,默认为true     boolean required = determineRequiredStatus(ann);     // 3. 将field封装成InjectedElement,并添加到集合中,这里用的是AutowiredFieldElement     currElements.add(new AutowiredFieldElement(field, required));    }   });   // 4. @Autowired可以注解在方法上   ReflectionUtils.doWithLocalMethods(targetClass, method -> {    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);    if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {     return;    }    MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);    if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {     if (Modifier.isStatic(method.getModifiers())) {      if (logger.isInfoEnabled()) {       logger.info("Autowired annotation is not supported on static methods: " + method);      }      return;     }     if (method.getParameterCount() == 0) {      if (logger.isInfoEnabled()) {       logger.info("Autowired annotation should only be used on methods with parameters: " +         method);      }     }     boolean required = determineRequiredStatus(ann);     PropertyDescriptor pd = BeanUtils.findPropertyFORMethod(bridgedMethod, clazz);     // 5. 将方法封装成InjectedElement,并添加到集合中,这里用的是AutowiredMethodElement     currElements.add(new AutowiredMethodElement(method, required, pd));    }   });   elements.addAll(0, currElements);   // 返回直接继承的父类   targetClass = targetClass.getSuperclass();  }  // 如果父类不为空则需要把父类的@Autowired属性或方法也找出  while (targetClass != null && targetClass != Object.class);  // 6. new InjectionMetadata(clazz, elements),将找到的所有的待注入属性或方法生成metadata返回  return InjectionMetadata.forElements(elements, clazz); }
  • 外层 do &hellip; while &hellip; 的循环被用于递归的查找父类的@Autowired属性或方法

  • 通过反射的方式获取到所有属性并循环验证每一个属性是否被@Autowired注解

  • 将查找到包含@Autowired注解的filed封装成AutowiredFieldElement,加入到列表中

  • 循环查找在方法上的注解

  • 将找到的方法封装成AutowiredMethodElement,并加入列表

这里需要特别强调一点,InjectedElementAutowiredFieldElementAutowiredMethodElement所继承,他们都有各自的inject函数,实现各自的注入。因此改ArrayList elements是拥有2种类型的属性

Java的@Autowired原理是什么

  • 将找到的所有元素列表和clazz作为参数生成metadata数据返回

2. 注入

// 注入metadata.inject(bean, beanName, pvs); 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);    }    // 循环注入,这里有可能是AutowiredFieldElement也可能AutowiredMethodElement,因此调用的inject是2个不同的方法    element.inject(target, beanName, pvs);   }  } }

利用for循环,遍历刚刚我们查到到的elements列表,进行注入。

在上面有特别提醒,这里的element有可能是AutowiredFieldElement类型、或AutowiredMethodElement类型。各自代表@Autowired注解在属性上、以及注解在方法上的2种不同元素。因此他们调用的element.inject(target, beanName, pvs);也是不一样的

2.1 字段注入(AutowiredFieldElement)
 private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {  @Override  protected void inject(Object bean, @Nullable String beanName, @Nullable 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);    // 设置class    desc.setContaininGClass(bean.getClass());    // 需要被自动注入的beanNames,这里只有可能 = 1,方法注入时才有可能为多个    Set<String> autowiredBeanNames = new LinkedHashSet<>(1);    Assert.state(beanFactory != null, "No BeanFactory available");    TypeConverter typeConverter = beanFactory.getTypeConverter();// 获取类型转换器    try {     // 通过beanFactory获取属性对应的值,比如需要调用getBean("b")获取依赖的属性单例,并且通过自动转型转为需要的类型     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);       // 因为是属性注入,因此这里只有可能等于1       if (autowiredBeanNames.size() == 1) {        String autowiredBeanName = autowiredBeanNames.iterator().next();        if (beanFactory.containsBean(autowiredBeanName) &&          beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {         // 缓存当前value         this.cachedFieldValue = new ShortcutDependencyDescriptor(           desc, autowiredBeanName, field.getType());        }       }      }      else {       this.cachedFieldValue = null;      }      this.cached = true;     }    }   }   if (value != null) {    // 通过反射,将value值设置到bean中    ReflectionUtils.makeAccessible(field);    field.set(bean, value);   }  } }

上方大部分的工作都在做待注入bean的获取以及类型的转换,如果深究下去可以再把spring ioc讲一遍,但是核心还是getBean(字段)获取到对应bean&hellip;我们这里就关心核心的语句,就是这2句

if (value != null) {    // 通过反射,将value值设置到bean中    ReflectionUtils.makeAccessible(field);    field.set(bean, value);}

spring通过反射的方式,调用field的set进行属性的注入

2.2 方法注入(AutowiredMethodElement)
 private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {  @Override  protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {   if (checkPropertySkipping(pvs)) {    return;   }   // @Autowired标注在方法上   Method method = (Method) this.member;   Object[] arguments;   if (this.cached) {    // Shortcut for avoiding synchronization...    // 有缓存    arguments = resolveCachedArguments(beanName);   }   else {    // 没缓存,直接获取方法上所有的参数    int argumentCount = method.getParameterCount();    arguments = new Object[argumentCount];    DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];    Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);    Assert.state(beanFactory != null, "No BeanFactory available");    TypeConverter typeConverter = beanFactory.getTypeConverter();    // 循环所有参数    for (int i = 0; i < arguments.length; i++) {     MethodParameter methodParam = new MethodParameter(method, i);     DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);     currDesc.setContainingClass(bean.getClass());     descriptors[i] = currDesc;     try {      // 通过beanFactory,获取代注入的bean,并进行类型转换      Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);      if (arg == null && !this.required) {       arguments = null;       break;      }      arguments[i] = arg;     }     catch (BeansException ex) {      throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);     }    }    synchronized (this) {     if (!this.cached) {      if (arguments != null) {       DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);       // 注册依赖       registerDependentBeans(beanName, autowiredBeans);       // 如果自动注入的个数 = 参数个数,则缓存       if (autowiredBeans.size() == argumentCount) {        Iterator<String> it = autowiredBeans.iterator();        Class<?>[] paramTypes = method.getParameterTypes();        for (int i = 0; i < paramTypes.length; i++) {         String autowiredBeanName = it.next();         if (beanFactory.containsBean(autowiredBeanName) &&           beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {          // 缓存          cachedMethodArguments[i] = new ShortcutDependencyDescriptor(            descriptors[i], autowiredBeanName, paramTypes[i]);         }        }       }       // 缓存方法       this.cachedMethodArguments = cachedMethodArguments;      }      else {       this.cachedMethodArguments = null;      }      this.cached = true;     }    }   }   if (arguments != null) {    try {     // 反射调用注入方法,将获取到的所有bean作为参数     ReflectionUtils.makeAccessible(method);     method.invoke(bean, arguments);    }    catch (InvocationTargetException ex) {     throw ex.getTargetException();    }   }  } }

这里与属性注入最大的区别在于,@Autowired注解在方法上,方法可以拥有多个参数,因此这里需要通过循环将一个个获取,而获取bean的方式于上面一样,本质都是通过getBean获取。

而核心语句还是2句

// 反射调用注入方法,将获取到的所有bean作为参数ReflectionUtils.makeAccessible(method);method.invoke(bean, arguments);

与属性注入不同的是,当@Autowired注解在方法上,例如我们注解在setter方法上,则只需要直接调用该setter方法将参数数组传入即可以,即使用invoke触发方法,具体属性赋值的过程在setter方法中由用户自行编写

到此,相信大家对“Java的@Autowired原理是什么”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: Java的@Autowired原理是什么

本文链接: https://lsjlt.com/news/341973.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java的@Autowired原理是什么
    本篇内容主要讲解“Java的@Autowired原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java的@Autowired原理是什么”吧!@Autowired使用构造函数注入publ...
    99+
    2023-07-02
  • Java超详细分析@Autowired原理
    目录@Autowired使用@Autowired源码分析1.查找所有@Autowired2. 注入2.1 字段注入(AutowiredFieldElement)2.2 方法注入(Au...
    99+
    2024-04-02
  • @Autowired的原理和作用
    这篇文章主要介绍“@Autowired的原理和作用”,在日常操作中,相信很多人在@Autowired的原理和作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”@Autowir...
    99+
    2024-04-02
  • @Autowired的作用是什么?
    @Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。常见用法:i...
    99+
    2021-06-10
    java教程 Autowired java
  • java treeset的原理是什么
    Java TreeSet是基于红黑树实现的有序集合的数据结构。红黑树是一种自平衡二叉查找树,它是通过对每个节点增加存储位来实现的,这...
    99+
    2023-09-09
    Java TreeSet
  • Java中的netty原理是什么
    一、 Netty简介Netty是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Lis...
    99+
    2020-04-09
    java教程 java netty 原理
  • Java的执行原理是什么
    这篇文章主要讲解了“Java的执行原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java的执行原理是什么”吧!一、编写java源程序java源文件...
    99+
    2024-04-02
  • java中RMI的原理是什么
    这篇文章主要介绍了java中RMI的原理是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、说明Client 端有一个被称 Stub 的东西,有时也会被成为存根,它是 R...
    99+
    2023-06-15
  • java中orm的原理是什么
    小编给大家分享一下java中orm的原理是什么,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网页开发;5. 企业...
    99+
    2023-06-14
  • java中Hibernate的原理是什么
    这篇文章将为大家详细讲解有关java中Hibernate的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况...
    99+
    2023-06-14
  • Java中Lock的原理是什么
    Java中Lock的原理是什么?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现了面...
    99+
    2023-06-14
  • java中Lombok的原理是什么
    本篇文章为大家展示了java中Lombok的原理是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌...
    99+
    2023-06-14
  • java中IO的原理是什么
    本篇文章为大家展示了java中IO的原理是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、IO概念I/O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和...
    99+
    2023-06-20
  • Java中TypeToken的原理是什么
    Java中TypeToken的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。泛型擦除众所周知,Java的泛型只在编译时有效,到了运行时这个泛型类型就会被擦除掉,即...
    99+
    2023-06-15
  • java 中ThreadPoolExecutor的原理是什么
    这篇文章将为大家详细讲解有关java 中ThreadPoolExecutor的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java 中ThreadPoolExecutor原理分析...
    99+
    2023-05-31
    java threadpoolexecutor ava
  • Java@Autowired注解底层原理详细分析
    目录1.概念2.注入数据的注解3.@Autowired注解是如何实现的1.概念 @Autowired 是 Spring 提供的注解,默认的注入方式为 byType (按类型自动注入)...
    99+
    2022-11-13
    Java @Autowired注解 Java @Autowired Java @Autowired原理
  • java动态代理的原理是什么
    小编给大家分享一下java动态代理的原理是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、说明使用代理将对象包装起来,然后用该代理对象取代原始对象。任何对原...
    99+
    2023-06-15
  • java原子类实现的原理是什么
    Java原子类的实现原理是利用了底层的CAS(Compare and Swap)操作。CAS是一种乐观锁机制,它包含三个参数:内存位...
    99+
    2023-10-18
    java
  • java中枚举的原理是什么
    java中枚举的原理是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3...
    99+
    2023-06-14
  • java中多态的原理是什么
    今天就跟大家聊聊有关java中多态的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;2...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作