从源码层面带你实现一个自动注入注解

如何自己实现一个自动注入的注解


  • 首先,需要了解到的是。Spring Bean 的生命周期
  • 在生命周期中。注入bean属性的位置是在以下代码:populateBean 位置中
  • 那么我们在项目中使用注解 产生一个bean的时候必定会经过以下代码进行一个bean的创建流程
/**省略代码**/
// 开始初始化 bean 实例对象
Object exposedObject = bean;
try {
    // <5> 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
    populateBean(beanName, mbd, instanceWrapper);
    // <6> 调用初始化方法
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    }
    else {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}
/**省略代码**/
  • 在生命周期中 populateBean 进行填充bean数据。把其他依赖引入进来
  • BeanPostProcessor 是一个bean创建时候的一个钩子。
  • 以下代码 是循环调用实现了 BeanPostProcessor 子类 InstantiationAwareBeanPostProcessor#postProcessProperties 方法
  • Spring 在以下代码中有自动注入的拓展点。 关键就是实现 InstantiationAwareBeanPostProcessor#postProcessProperties
/**省略代码**/
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        // 对所有需要依赖检查的属性进行后处理
        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
            // 从 bw 对象中提取 PropertyDescriptor 结果集
            // PropertyDescriptor:可以通过一对存取方法提取一个属性
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return;
            }
        }
        pvs = pvsToUse;
    }
}
/**省略代码**/
  • 我们展开来讲一下 @Autowired 的实现是怎么样的吧:
  • 实现类为 AutowiredAnnotationBeanPostProcessor.java
  • 从上面可以得知,填充bean的时候。时调用了方法 ibp.postProcessPropertyValues()
  • 那么 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues() 则会被调用
  • 调用 findAutowiringMetadata 获取 class 以及父类 带有 @Autowired 或者 @Value 的属性或者方法:
/**省略代码**/
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // 获取所有可以注入的元数据
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        // 注入数据
        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;
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    // 缓存名字获取
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    // 获取是否已经读取过这个 class 类的 InjectionMetadata 有的话直接从缓存中获取出去
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            // 双重检查
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                // 构建自动注入的元数据
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }

    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        // 循环 targetClass 的所有 field 并执 FieldCallback 逻辑 (函数式编程接口,传入的是一个执行函数)
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // 获得字段上面的 Annotation 注解
            MergedAnnotation<?> ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // 判断是否为静态属性 如果是,则不进行注入
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isInfoEnabled()) {
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值