spring源码分析(五)@Autowire注入补充,@Resource源码分析

2021/6/3 22:21:00

本文主要是介绍spring源码分析(五)@Autowire注入补充,@Resource源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

自动注入补充的点:

1:AutowireMode

之前博客中讲到@Autowire,@Value,@Inject自动注入的处理都是在后置处理器 AutowiredAnnotationBeanPostProcessor#postProcessProperties中,这个后置处理器的调用是在 AbstractAutowireCapableBeanFactory#populateBean 中:

 但是在这段逻辑上面有一段 AutowireMode的判断,会根据bean对应的BeanDefinition中的 AutowireMode属性判断是否要走byType, byName。但是这段逻辑很少走到,因为平常用的@Component,@Service ,@Bean生成的 BeanDefinition#getResolvedAutowireMode()结果都是AUTOWIRE_NO

 

除了在xml定义bean的时候可以设置autowire属性:  <bean id="people" class="com.my.ioc.pojo.People" autowire="byName">

在使用@Bean定义bean的时候也可以定义这个属性,但是推荐已经过期了:

 

 


 

2:@Lazy

注入点的属性加了@Lazy之后的处理逻辑,上篇中还没有提到,在DefaultListableBeanFactory#resolveDependency 中,

属性注入的对象只是个代理对象,当调用对象的相应方法时,会调用getTarget()得到真实的对象,也还是调用doResolveDependency方法。

 


 

3:bean自动注入自身对象

    加入定义了三个类型为People的bean, beanName分别是 people, people1,people2,  我在people的定义中注入自身。

@Component
public class People {

   @Autowired
   private People people;
   private String userName="people";

   public People(String userName) {
      this.userName = userName;
   }

   public People() {
   }
    public String getFieldPeopleUserName(){
      return people.getUserName();
   }

 

config中定义了两个:

    @Bean
    @Scope("prototype")
    public People people1()
    {
        People p1= new People();
        p1.setUserName("people1");
        return p1;
    }

    @Bean
    @Scope("prototype")
    public People people2(){
        People p1= new People();
        p1.setUserName("people2");
        return p1;
    }

 

去geBean("people");

       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
      System.out.println("======================");
      People son=(People)applicationContext.getBean("people");
      System.out.println(son.getFieldPeopleUserName());
      System.out.println("======================");

 

执行是会报错的:这里它只找到了两种people1,people2两个bean。   注意这里并没有把people找出来。

 

 把people2的@Bean注释掉之后,再次执行是可以成功的。但是注意哦,这里属性注入的实例是beanName为people1的。

 

把people1也注释掉,就只有people一个。属性注入也是可以成功。

 

 

 为什么会出现上面两种情况呢?要从DefaultListableBeanFactory#findAutowireCandidates 的源码中得知。再找到候选者beanName之后会经过 isAutowireCandidate的筛选,但是筛选之前还有个判断,就是根据byType找到的beanName是不是自身。如果是自身的话result中就不会存这个beanName。isSelfReference这个方法。

// 对候选者bean进行过滤,首先候选者不是自己,然后候选者是支持自动注入给其它beand的
        // 这里判断是不是候选者的时候不止会判断 autowire-candidate是否为true,还有一些其它判断:isAutowireCandidate(candidate, descriptor)
        for (String candidate : candidateNames) {
            // 根据byType找到的beanName判断 isSelfReference(beanName, candidate) 首先排除了候选者是自己
            // isAutowireCandidate方法中会去判断候选者是否和descriptor匹配 并不是所有bean都是可以进行注入的
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        // 如果只有一个people,上面过滤后result为空。
        if (result.isEmpty()) {
            boolean multiple = indicatesMultipleBeans(requiredType);
            // Consider fallback matches if the first pass failed to find anything...
            DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
            for (String candidate : candidateNames) {
                if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
                        (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
            if (result.isEmpty() && !multiple) {
                // Consider self references as a final pass...
                // but in the case of a dependency collection, not the very same bean itself.
                for (String candidate : candidateNames) {
                    // 如果上面的result都为空,判断是否是自身注入,如果是的就把自身的bean添加到result中
                    if (isSelfReference(beanName, candidate) &&
                            (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
                            isAutowireCandidate(candidate, fallbackDescriptor)) {
                        addCandidateEntry(result, candidate, descriptor, requiredType);
                    }
                }
            }
        }
        return result;

 

1)如果有people,people1,people2三个beanName的People。经过上面的逻辑之后,result还有两个people1,people2,然后返回给DefaultListableBeanFactory#doResolveDependency

    返回的这个matchingBeans有两个。在调用determineAutowireCandidate 要确定唯一  一个beanName的时候是没法确定的,因为属性名是people,所以会走到descriptor.resolveNotUnique  抛出错误。

 

 2:当把people2注释掉之后,返回的result中就剩下people2一个beanName,所以注入的就是这个,不会再报错。

 

3:注释掉people1之后,就只有people自己了,注入自身people也是成功的,这是为啥呢?  候选者bean筛选的时候是去掉自身的bean了吗。是的,候选者bean筛选的时候是去掉自身的bean,这时候在DefaultListableBeanFactory#findAutowireCandidates方法筛选之后,result 为空,但是下面如果筛选结果为空,又有一些判断,其中就把所有的候选者beanName又过滤一遍,如果有自身的beanname就添加进了result中了,

所以返回的结果中,就只有自身的beanName了。

 

 


 @Resource

注入的流程先作个总结再看源码:

1:如果@Resource中指定了name属性,则只会根据这个name属性值去找bean,找不到就报错。

2:如果没有指定这个name属性,那么先判断注入点的名字(属性名/set方法名)是不是存在bean,如果存在,则直接根据注入点名字获取bean注入。

      如果不存在,则会走@Autowire的注入逻辑,根据注入点类型去找bean。

我们上篇提到@Autowire自动注入的的源码是在后置处理器AutowiredAnnotationBeanPostProcessor 中的,但是@Resource的注解的解析注入是在 CommonAnnotationBeanPostProcessor中实现的。

CommonAnnotationBeanPostProcessor  继承了 InitDestroyAnnotationBeanPostProcessor,实现了InstantiationAwareBeanPostProcessor,所以也有postProcessMergedBeanDefinition ,postProcessProperties方法。

 

 

 了解了@Autowire的源码,这个就很简单了,流程基本都是一样的。但是这个后置处理器并不是单独处理@Resource注解的,这是个公共的后置处理器,还会处理其它注解。

@Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
        // 找到注入点
        InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        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 = buildResourceMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
   if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
   }
   List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
   Class<?> targetClass = clazz;
   do {
      // 注意,下面InjectedElement子类不再按属性和方法分了,而是按注解类型来分了
      final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
           // 找到属性上面的注解
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
         // 判断属性上是否有 javax.xml.ws.WebServiceRef 注解
         if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
            if (Modifier.isStatic(field.getModifiers())) {
               throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
            }
            currElements.add(new WebServiceRefElement(field, field, null));
         }
         //判断判断属性上是否有 javax.ejb.EJB
         else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
            if (Modifier.isStatic(field.getModifiers())) {
               throw new IllegalStateException("@EJB annotation is not supported on static fields");
            }
            currElements.add(new EjbRefElement(field, field, null));
         }
         // 判断属性上是否有 @Resource注解
         else if (field.isAnnotationPresent(Resource.class)) {
            // 不能注入静态属性
            if (Modifier.isStatic(field.getModifiers())) {
               throw new IllegalStateException("@Resource annotation is not supported on static fields");
            }
            // 可以向ignoredResourceTypes添加不想被注入的类型,当ignoredResourceTypes包含属性的类型时,这个属性不作为注入点
            if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
            //  构造方法中会根据是否在注解上传入了name属性来给this.name 赋值
               currElements.add(new ResourceElement(field, field, null));
            }
         }
      });
      // 判断方法上是否有相关注解
      ReflectionUtils.doWithLocalMethods(targetClass, method -> {
         Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
         if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
            return;
         }
         if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
            if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
               if (Modifier.isStatic(method.getModifiers())) {
                  throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
               }
               if (method.getParameterCount() != 1) {
                  throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
               }
               PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
               currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
            }
            else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
               if (Modifier.isStatic(method.getModifiers())) {
                  throw new IllegalStateException("@EJB annotation is not supported on static methods");
               }
               if (method.getParameterCount() != 1) {
                  throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
               }
               PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
               currElements.add(new EjbRefElement(method, bridgedMethod, pd));
            }
            else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
               // 不能加在静态方法上
               if (Modifier.isStatic(method.getModifiers())) {
                  throw new IllegalStateException("@Resource annotation is not supported on static methods");
               }
               Class<?>[] paramTypes = method.getParameterTypes();
               // @Resource 加的方法上的参数必须只有一个
               if (paramTypes.length != 1) {
                  throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
               }
               // ignoredResourceTypes 包含参数的类型的话 这个方法也是不作为注入点的
               if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                  PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                  currElements.add(new ResourceElement(method, bridgedMethod, pd));
               }
            }
         }
      });

      elements.addAll(0, currElements);
      // 还是会向上找父类的
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);

   return InjectionMetadata.forElements(elements, clazz);
}
 

public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
            super(member, pd);
            Resource resource = ae.getAnnotation(Resource.class);
            String resourceName = resource.name();
            Class<?> resourceType = resource.type();
            // 这里判断,@Resource有没有设置name属性值,如果没有的话,把this.isDefaultName=true
            // 默认的名字 this.name 就被赋值为了属性名resourceName = this.member.getName(); 得到属性名
            this.isDefaultName = !StringUtils.hasLength(resourceName);
            if (this.isDefaultName) {
                resourceName = this.member.getName();
                if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
                    resourceName = Introspector.decapitalize(resourceName.substring(3));
                }
            }
            else if (embeddedValueResolver != null) {
                resourceName = embeddedValueResolver.resolveStringValue(resourceName);
            }
            if (Object.class != resourceType) {
                checkResourceType(resourceType);
            }
            else {
                // No resource type specified... check field/method.
                resourceType = getResourceType();
            }
            this.name = (resourceName != null ? resourceName : "");
            this.lookupType = resourceType;
            String lookupValue = resource.lookup();
            this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
            Lazy lazy = ae.getAnnotation(Lazy.class);
            this.lazyLookup = (lazy != null && lazy.value());
        }

 

注意:  @Resource不能加在静态属性和方法上,加上方法上,方法的参数必须只有一个,可以通过 this.ignoredResourceTypes 去掉不想被注入的类型。

上面找到注入点之后,下面就进行注入 ,  执行的方法:CommonAnnotationBeanPostProcessor#postProcessProperties 方法,

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
        }
        return pvs;
    }
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectedElement> elementsToIterate =
                (checkedElements != null ? checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            //遍历每个能够注入的属性 进行注入
            for (InjectedElement element : elementsToIterate) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                }
                // element可能是Method 也可能是Field 会走不同的子类   AutowiredFieldElement  AutowiredMethodElement
               
                //  在@Resource逻辑里,那些注入的子类,并没有重写inject方法,还是走的 InjectedElement#inject
                element.inject(target, beanName, pvs);
            }
        }
    }
InjectedElement#inject
/**
 * Either this or {@link #getResourceToInject} needs to be overridden.
 */
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
      throws Throwable {
           // 如果时属性则反射赋值
if (this.isField) {
      Field field = (Field) this.member;
      ReflectionUtils.makeAccessible(field);
      //getResourceToInject 需要被重写,就是ResourceElement
field.set(target, getResourceToInject(target, requestingBeanName));
   }
   else {
      // 检查当前的属性是不是通过 by type 和by name注入的
if (checkPropertySkipping(pvs)) {
         return;
      }
      try {
         // 如果时方法,则通过方法赋值
Method method = (Method) this.member;
         ReflectionUtils.makeAccessible(method);
         method.invoke(target, getResourceToInject(target, requestingBeanName));
      }
      catch (InvocationTargetException ex) {
         throw ex.getTargetException();
      }
   }
}

 

ResourceElement#getResourceElement

@Override
        protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
            return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
                    getResource(this, requestingBeanName));
        }

 

看getResource

protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
            throws NoSuchBeanDefinitionException {

        if (StringUtils.hasLength(element.mappedName)) {
            return this.jndiFactory.getBean(element.mappedName, element.lookupType);
        }
        if (this.alwaysUseJndiLookup) {
            return this.jndiFactory.getBean(element.name, element.lookupType);
        }
        if (this.resourceFactory == null) {
            throw new NoSuchBeanDefinitionException(element.lookupType,
                    "No resource factory configured - specify the 'resourceFactory' property");
        }
        return autowireResource(this.resourceFactory, element, requestingBeanName);
    }
autowireResource,里面逻辑主要也是resolveDependency.这部分见@Autowire分析
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
            throws NoSuchBeanDefinitionException {

        Object resource;
        Set<String> autowiredBeanNames;
        String name = element.name;

        if (factory instanceof AutowireCapableBeanFactory) {
            AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
            DependencyDescriptor descriptor = element.getDependencyDescriptor();
            // 如果isDefaultName 为true说明@Resource没有配置属性name属性,默认的是属性名。 !factory.containsBean(name) 且bean工厂中不含有这个bean
            //  走这里之前 fallbackToDefaultTypeMatch 这个才是第一个开关 相当于看是否需要根据Type进行找bean
            if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
                autowiredBeanNames = new LinkedHashSet<>();
                // 走到 resolveDependency  这个是@Autowire的逻辑是一样的  先byType 在byName找bean
                resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
                if (resource == null) {
                    throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
                }
            }
            else {
                // 直接从beanFactory中获取bean
                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;
            for (String autowiredBeanName : autowiredBeanNames) {
                if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                    beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
                }
            }
        }

        return resource;
    }

 



这篇关于spring源码分析(五)@Autowire注入补充,@Resource源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程