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


    一. 认识·@Autowired

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

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

    [使用@Autowired注解注入Bean]

    1. @Autowired
    2. public IAccountDao dao;
    1. @Autowired
    2. 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实现的。

    1. public AutowiredAnnotationBeanPostProcessor() {
    2. this.autowiredAnnotationTypes.add(Autowired.class);
    3. this.autowiredAnnotationTypes.add(Value.class);
    4. try {
    5. this.autowiredAnnotationTypes.add(ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
    6. this.logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
    7. } catch (ClassNotFoundException var2) {
    8. }
    9. }

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

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

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

    1. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    2. BeanWrapper instanceWrapper = null;
    3. if (mbd.isSingleton()) {
    4. instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    5. }
    6. // 1.处理自动注入构造方法
    7. if (instanceWrapper == null) {
    8. instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    9. }
    10. Object bean = instanceWrapper.getWrappedInstance();
    11. Class beanType = instanceWrapper.getWrappedClass();
    12. if (beanType != NullBean.class) {
    13. mbd.resolvedTargetType = beanType;
    14. }
    15. synchronized(mbd.postProcessingLock) {
    16. if (!mbd.postProcessed) {
    17. try {
    18. // 2.扫描注解并注入
    19. this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    20. } catch (Throwable var17) {
    21. throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
    22. }
    23. mbd.postProcessed = true;
    24. }
    25. }
    26. ......
    27. private T populateBean(ResultSet rs, T bean, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
    28. for(int i = 1; i < columnToProperty.length; ++i) {
    29. if (columnToProperty[i] != -1) {
    30. PropertyDescriptor prop = props[columnToProperty[i]];
    31. Class propType = prop.getPropertyType();
    32. Object value = null;
    33. if (propType != null) {
    34. value = this.processColumn(rs, i, propType);
    35. if (value == null && propType.isPrimitive()) {
    36. value = primitiveDefaults.get(propType);
    37. }
    38. }
    39. // 存入Bean
    40. this.callSetter(bean, prop, value);
    41. }
    42. }
    43. return bean;
    44. }

     

  • 相关阅读:
    信号量机制实现进程互斥,进程同步,进程的前驱关系
    C++ Tutorials: C++ Language: Compound data types: Arrays
    qemu-system-aarch64使用记录
    【Unity3D】UI Toolkit元素
    Vue:(四)数据代理
    路西法98-生活记录ing
    设计模式的介绍
    Node.js C++ 层的任务管理
    自己动手从零写桌面操作系统GrapeOS系列教程——24.加载并运行loader
    计算机组成原理(七)
  • 原文地址:https://blog.csdn.net/weixin_45939128/article/details/127539743