Spring:@Autowired自动装配的实现原理

@Autowired

含义:向属性注入JavaBea,默认按照类型通过set方法进行自动装配。

如果spring容器中没有可以与之匹配的类则会报错:NoSuchBeanDefinitionException。

 如果spring容器有多个类型可以匹配,@Autowired注解会自动切换为按照名称(属性名)匹配,如果还没有则会报错:NoUniqueBeanDefinitionException。

 在bean的生命周期中,贯穿着很多后置处理器,这些处理器为bean的生命周期各阶段提供拓展。属性赋值阶段是在bean实例化后立即执行。@Autowired注解的实现过程就是调用了AutowiredAnnotationBeanPostProcessor类中的方法。

核心方法postProcessProperties:

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//1.获取当前类中标注了@Autowired的成员变量和方法的参数封装在metadata对象里
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);

        try {
//2.利用反射赋值
            metadata.inject(bean, beanName, pvs);
            return pvs;
        } catch (BeanCreationException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
        }
    }

1.调用findAutowiringMetadata方法查询

  private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        //获取当前bean的名称
        String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();
       //在缓存中查找是否有当前类的信息
 InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized(this.injectionMetadataCache) {
                metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                //调用此方法解析当前类,获得所有标注@AutoWired的字段 并存入metada中
                    metadata = this.buildAutowiringMetadata(clazz);
                //存入缓存中
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        //返回得到@AutoWired的字段的metadata
        return metadata;
    }

2.执行inject方法完成属性注入

 public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        //metadata中的数据放在集合中
        Collection<InjectionMetadata.InjectedElement> checkedElements = this.checkedElements;

       Collection<Injectio
nMetadata.InjectedElement> elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;

        if (!((Collection)elementsToIterate).isEmpty()) {
            Iterator var6 = ((Collection)elementsToIterate).iterator();
//遍历集合拿到标注了@AutoWired的成员变量和方法
            while(var6.hasNext()) {
                InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();
//遍历调用内部类的方法完成属性赋值
                element.inject(target, beanName, pvs);
            }
        }

    }

内部类的inject方法

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
               //判断是方法还是成员变量
            if (this.isField) {
                //得到bean的Field对象
                Field field = (Field)this.member;
                //底层做了判断然后停止修饰符检查
                ReflectionUtils.makeAccessible(field);
                //利用反射给成员变量赋值 
                field.set(target, this.getResourceToInject(target, requestingBeanName));
            } else {
                if (this.checkPropertySkipping(pvs)) {
                    return;
                }

                try {
                //得到bean的方法对象
                    Method method = (Method)this.member;
                    //停止修饰符检查
                    ReflectionUtils.makeAccessible(method);
                    //利用invoke给targe赋值,值为此方法的返回值
                    method.invoke(target, this.getResourceToInject(target, requestingBeanName));
                } catch (InvocationTargetException var5) {
                    throw var5.getTargetException();
                }
            }

        }

此处的getResourceToInject方法返回为null,调用的应该是其他子类的重写方法

 查看类的结构发现有重写的:此方法判断加载类型:

 第一种是用懒加载:使用代理模式,先返回代理对象。等需要时在调用getResource方法获得被代理的对象。

第二种就是直接赋值:底层会调用本类中的autowireResource方法,在BeanFactory中根据名称查找是所需bean的对象。完成属性赋值。

 protected Object autowireResource(BeanFactory factory, CommonAnnotationBeanPostProcessor.LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException {
        String name = element.name;
        Object resource;
        Object autowiredBeanNames;
        if (factory instanceof AutowireCapableBeanFactory) {
            AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory)factory;
            DependencyDescriptor descriptor = element.getDependencyDescriptor();
            if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
                autowiredBeanNames = new LinkedHashSet();
                resource = beanFactory.resolveDependency(descriptor, requestingBeanName, (Set)autowiredBeanNames, (TypeConverter)null);
                if (resource == null) {
                    throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
                }
            } else {
                resource = beanFactory.resolveBeanByName(name, descriptor);
                autowiredBeanNames = Collections.singleton(name);
            }
        } else {
            resource = factory.getBean(name, element.lookupType);
            autowiredBeanNames = Collections.singleton(name);
        }

        if (factory instanceof ConfigurableBeanFactory) {
            ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)factory;
            Iterator var11 = ((Set)autowiredBeanNames).iterator();

            while(var11.hasNext()) {
                String autowiredBeanName = (String)var11.next();
                if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                    beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
                }
            }
        }

        return resource;
    }

这里面底层调用了很多方法,做了大量的判断。我也只是一个新手,尽量写出自己的理解,有很多地方也很模糊,也借阅了其他大佬的解读。

此地址为参考文章。

http://t.csdn.cn/xScoi

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值