• @Autowired注解底层是如何实现的


    1.概念:

            @Autowired 是 Spring 提供的注解,默认的注入方式为 byType (按类型自动注入);@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作;通过 @Autowired的使用来消除 set ,get方法。

    2.注入数据的注解:

    @Value
        含义:通过set方式注入基本类型与String,set方法可以省略
        语法:@Value("数据")/@Value("${key}")
        位置:修饰属性,set方法
        注意:如果动态获取必须指定加载资源文件                                                                                                  

        @Autowired
        替换:autowire属性,自动装配(按照类型装配,通过set方法,且方法可以省略)
        位置:修饰属性,set方法
        语法:@Autowired(required="true")
        注意:1.如果容器中没有一个可以与之匹配且required属性为true则会报异常
                      NoSuchBeanDefinitionException
                   2.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配
                   3.如果名称也没有匹配,则报异常NoUniqueBeanDefinitionException

    3.@Autowired注解是如何实现的:

            @Autowired注解在spring源代码里的定义:

    1. package org.springframework.beans.factory.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface Autowired {
    11. boolean required() default true;
    12. }

    通过代码看到Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。

    在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,实现逻辑位于类:AutowiredAnnotationBeanPostProcessor之中。

    核心处理代码如下:

    1. private InjectionMetadata buildAutowiringMetadata(final Class clazz) {
    2. LinkedList elements = new LinkedList<>();
    3. Class targetClass = clazz;//需要处理的目标类
    4. do {
    5. final LinkedList currElements = new LinkedList<>();
    6. /*通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性*/
    7. ReflectionUtils.doWithLocalFields(targetClass, field -> {
    8. AnnotationAttributes ann = findAutowiredAnnotation(field);
    9. if (ann != null) {//校验autowired注解是否用在了static方法上
    10. if (Modifier.isStatic(field.getModifiers())) {
    11. if (logger.isWarnEnabled()) {
    12. logger.warn("Autowired annotation is not supported on static fields: " + field);
    13. }
    14. return;
    15. }//判断是否指定了required
    16. boolean required = determineRequiredStatus(ann);
    17. currElements.add(new AutowiredFieldElement(field, required));
    18. }
    19. });
    20. //和上面一样的逻辑,但是是通过反射处理类的method
    21. ReflectionUtils.doWithLocalMethods(targetClass, method -> {
    22. Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
    23. if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    24. return;
    25. }
    26. AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
    27. if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    28. if (Modifier.isStatic(method.getModifiers())) {
    29. if (logger.isWarnEnabled()) {
    30. logger.warn("Autowired annotation is not supported on static methods: " + method);
    31. }
    32. return;
    33. }
    34. if (method.getParameterCount() == 0) {
    35. if (logger.isWarnEnabled()) {
    36. logger.warn("Autowired annotation should only be used on methods with parameters: " +
    37. method);
    38. }
    39. }
    40. boolean required = determineRequiredStatus(ann);
    41. PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
    42. currElements.add(new AutowiredMethodElement(method, required, pd));
    43. }
    44. });
    45. //用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理
    46. elements.addAll(0, currElements);
    47. targetClass = targetClass.getSuperclass();
    48. }
    49. while (targetClass != null && targetClass != Object.class);
    50. return new InjectionMetadata(clazz, elements);
    51. }

    最后这个方法返回的就是包含所有带有autowire注解修饰的一个InjectionMetadata集合。这个类由两部分组成:

    1. public InjectionMetadata(Class targetClass, Collection elements) {
    2. this.targetClass = targetClass;
    3. this.injectedElements = elements;
    4. }

    一是处理的目标类,二就是上述方法获取到的所以elements集合。

    有了目标类,与所有需要注入的元素集合之后,就可以实现autowired的依赖注入逻辑了,实现的方法如下:

    1. @Override
    2. public PropertyValues postProcessPropertyValues(
    3. PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    4. InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    5. try {
    6. metadata.inject(bean, beanName, pvs);
    7. }
    8. catch (BeanCreationException ex) {
    9. throw ex;
    10. }
    11. catch (Throwable ex) {
    12. throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    13. }
    14. return pvs;
    15. }

    它调用的方法是InjectionMetadata中定义的inject方法,如下

    1. public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    2. Collection checkedElements = this.checkedElements;
    3. Collection elementsToIterate =
    4. (checkedElements != null ? checkedElements : this.injectedElements);
    5. if (!elementsToIterate.isEmpty()) {
    6. for (InjectedElement element : elementsToIterate) {
    7. if (logger.isTraceEnabled()) {
    8. logger.trace("Processing injected element of bean '" + beanName + "': " + element);
    9. }
    10. element.inject(target, beanName, pvs);
    11. }
    12. }
    13. }

    其逻辑就是遍历,然后调用inject方法,inject方法其实现逻辑如下:

    1. protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
    2. throws Throwable {
    3. if (this.isField) {
    4. Field field = (Field) this.member;
    5. ReflectionUtils.makeAccessible(field);
    6. field.set(target, getResourceToInject(target, requestingBeanName));
    7. }
    8. else {
    9. if (checkPropertySkipping(pvs)) {
    10. return;
    11. }
    12. try {
    13. Method method = (Method) this.member;
    14. ReflectionUtils.makeAccessible(method);
    15. method.invoke(target, getResourceToInject(target, requestingBeanName));
    16. }
    17. catch (InvocationTargetException ex) {
    18. throw ex.getTargetException();
    19. }
    20. }
    21. }

    inject也使用了反射技术并且依然是分成字段和方法去处理的。

  • 相关阅读:
    马斯克热搜体质无疑,称已将大脑上传云端,却遭网友热议!
    【Java 基础篇】Java 接口组成与更新详解
    2023.10.02 win7x64sp1下Navicat_Premium15_x86连接Oracle_10g(安装在win2003x86)
    JSqlParser生成修改表定义SQL语句
    在任意位置插入
    14、ffmpeg中进进行硬件编码和解码的片段程序_cuda进行rgb2yuv和yuv2rgb
    嵌入式能从事什么职业?
    leetcode:142. 环形链表 II
    sqlalchemy expire_all 方法详解,强制刷新会话缓存
    学生用什么光的灯最好?适合学生光源的护眼台灯推荐
  • 原文地址:https://blog.csdn.net/weixin_52386948/article/details/127414459