当前位置: 首页 > news >正文

Spring常用注解——@Autowired自动装配的作用和原理

一. 认识·@Autowired

当我们在Spring框架中配置Bean时,常见的有三种办法:①使用xml ②使用注解 ③使用javeconfig。由于第一种方法需要在application.xml配置文件中使用大量<bean>标签来进行注入,就衍生了注解,我们只要使用@Autowired对成员变量、方法和构造函数进行标注,就可以来完成自动装配的工作, 通过 @Autowired的使用还可以消除 set ,get方法,大大减少了代码量。

eg:[使用xml配置文件注入Bean]

[使用@Autowired注解注入Bean]

  @Autowired
    public IAccountDao dao;
    @Autowired
    public IAccountService service;

二. 用法·@Autowired

 @Autowired
    替换:autowire属性,自动装配(默认按照类型装配,通过set方法,且方法可以省略)
    位置:修饰属性,set方法
    语法:@Autowired (默认为true)

@Autowired(required=false):表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错。

 @Autowired(required="true"):表示注入的时候,该bean必须存在,否则就会注入失败。
    注意:1.如果容器中没有一个可以与之匹配且required属性为true则会报异常 NoSuchBeanDefinitionException
         2.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配
         3.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配,如果名称也没有匹配,则报异常
            NoUniqueBeanDefinitionException

        4.@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier使用;

三.原理

看看源码:@Autowired 位于 org.springframework.beans.factory.annotation.Autowired包下,其实现原理就是调用了AutowiredAnnotationBeanPostProcessor类下的postProcessProperties()方法。

1.AutowiredAnnotationBeanPostProcessor是BeanPostProcesser的一个实现类它的主要功能就是对带注解的方法,set方法,和任意配置方法进行自动注入,这些注入的成员是通过注解来实现自动装配的。

在AutowiredAnnotationBeanPostProcessor类的构造方法中,我们可以看到,这些注解包括Spring的@Autowired和@Value注解,还支持JSR-330的@Inject注解(功能基本类似),这些注解都是基于AutowiredAnnotationBeanPostProcessor实现的。

 public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);

        try {
            this.autowiredAnnotationTypes.add(ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
            this.logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
        } catch (ClassNotFoundException var2) {
        }

    }

 (Bean的生命周期:实例化,属性赋值,初始化,操作使用,销毁)

AutowiredAnnotationBeanPostProcessor方法的调用,完成了扫描并处理自动注入的构造方法,之后会返回来doCreateBean方法中,所以其调用逻辑主要集中在doCreateBean()方法中,调用applyMergedBeanDefinitionPostProcessors方法,完成扫描并且注入属性和方法。

doCreateBean()主要分为三个部分,第一个部分是在实例化 Bean 的时候在 createBeanInstance 方法中会调用 AutowiredAnnotationBeanPostProcessor 中的方法来获取需要自动注入的构造方法,第二部分是调用 AutowiredAnnotationBeanPostProcessor 的方法来完成对所有需要自动注入的属性和方法的解析和缓存,最后一部分就是在 populatedBean 方法中调用到 AutowiredAnnotationBeanPostProcessor 中的方法来完成需要自动注入属性的注入工作。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
        // 1.处理自动注入构造方法
        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // 2.扫描注解并注入
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }
......
 private <T> T populateBean(ResultSet rs, T bean, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
        for(int i = 1; i < columnToProperty.length; ++i) {
            if (columnToProperty[i] != -1) {
                PropertyDescriptor prop = props[columnToProperty[i]];
                Class<?> propType = prop.getPropertyType();
                Object value = null;
                if (propType != null) {
                    value = this.processColumn(rs, i, propType);
                    if (value == null && propType.isPrimitive()) {
                        value = primitiveDefaults.get(propType);
                    }
                }

                // 存入Bean
                this.callSetter(bean, prop, value);
            }
        }

        return bean;
    }

 

相关文章:

  • 一些运维命令
  • 代码随想录动态规划——背包问题总结篇
  • web安全之信息收集
  • 基于FPGA的双目相机目标深度图像提取实现——详细版
  • 【饭谈】细嗦那些职场中喜欢用领导口气命令别人的同事
  • 10 通用同步异步收发器(USART)
  • AI绘图—对中文拟合度很高,值得一试
  • 【 C++11 】包装器
  • 【动手学深度学习PyTorch版】13 卷积层的填充和步幅
  • 第十三届蓝桥杯C++B组国赛H题——机房 (AC)
  • django框架技术沉淀
  • 血的教训---入侵redis并远程控制你的机器场景复现
  • 基于javaweb的养老院管理系统(java+springboot+thymeleaf+html+js+mysql)
  • 【CV】第 6 章:图像分类的实际方面
  • HazelEngine 学习记录 - Shader Asset Files
  • python3.6+scrapy+mysql 爬虫实战
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • Go 语言编译器的 //go: 详解
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Java IO学习笔记一
  • Python打包系统简单入门
  • scrapy学习之路4(itemloder的使用)
  • Shell编程
  • tensorflow学习笔记3——MNIST应用篇
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 力扣(LeetCode)22
  • 如何编写一个可升级的智能合约
  • 我从编程教室毕业
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 因为阿里,他们成了“杭漂”
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #Z2294. 打印树的直径
  • (0)Nginx 功能特性
  • (02)vite环境变量配置
  • (bean配置类的注解开发)学习Spring的第十三天
  • (Python) SOAP Web Service (HTTP POST)
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • ... 是什么 ?... 有什么用处?
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .chm格式文件如何阅读
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .net 微服务 服务保护 自动重试 Polly
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • /etc/fstab 只读无法修改的解决办法
  • @ModelAttribute使用详解