본문 바로가기

emotional developer/detect-Java

spring @autowired annotaion 동작

- 동작흐름.

1. beanfactory 에서 후보 bean을 가져온다. (by type) - @Qualifier 지정자가 있을 경우, 후보 bean을 지정자와 매치하는 것만 찾음

2-0. 후보가 없으면, 에러 끝.
2-1. 1개 일 경우, 반환 끝.
2-2. 2개 이상 일 경우. (fallback 상태)
이런 경우, fallback 상태로 처리 (is smart?)

2-2-1 
각 후보 bean 에서 primary 표시자 유무를 찾는다. (@Primary annotation)
있는 경우, primary 로 지정된 bean 을 반환. (2개 이상 primary 로 지정 하면?)

2-2-2
primary 조차 없는 경우.
filedname(변수명)과 동일한 bean id가 있다면 반환.

2-2-3
그것 조차 없으면, 에러.


code

AutowiredAnnotationBeanPostProcessor.inject
-> beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
-> DefaultListableBeanFactory.doResolveDependency
-> DefaultListableBeanFactory.findAutowireCandidates
-> DefaultListableBeanFactory.determinePrimaryCandidate

     /**
     * Determine the primary autowire candidate in the given set of beans.
     * @param candidateBeans a Map of candidate names and candidate instances
     * that match the required type, as returned by {@link #findAutowireCandidates}
     * @param descriptor the target dependency to match against
     * @return the name of the primary candidate, or <code>null</code> if none found
     */
     protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
          String primaryBeanName = null;
          String fallbackBeanName = null;
          for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
               String candidateBeanName = entry.getKey();
               Object beanInstance = entry.getValue();
               if (isPrimary(candidateBeanName, beanInstance)) {
                    if (primaryBeanName != null) {
                         boolean candidateLocal = containsBeanDefinition(candidateBeanName);
                         boolean primaryLocal = containsBeanDefinition(primaryBeanName);
                         if (candidateLocal == primaryLocal) {
                              throw new NoSuchBeanDefinitionException(descriptor.getDependencyType(),
                                        "more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
                         }
                         else if (candidateLocal && !primaryLocal) {
                              primaryBeanName = candidateBeanName;
                         }
                    }
                    else {
                         primaryBeanName = candidateBeanName;
                    }
               }
               if (primaryBeanName == null &&
                         (this.resolvableDependencies.values().contains(beanInstance) ||
                                   matchesBeanName(candidateBeanName, descriptor.getDependencyName()))) {
                    fallbackBeanName = candidateBeanName;
               }

          }
          return (primaryBeanName != null ? primaryBeanName : fallbackBeanName);
     }



참고)

@Autowired is type-driven but it provides a fallback catch to inject bean by name. Use @Resource if you want to perform a bean lookup and injection based on name, alternatively @Autowired along with @Qualifier can work as well, even though it is more useful when grouping beans. http://www.spiritwalker-jiang.com/archive/2013/02/11/Understanding-Autowired-annation-in-Spring


This is documented in section 3.9.3:

For a fallback match, the bean name is considered a default qualifier value.

In other words, the default behaviour is as though you'd added @Qualifier("country") to the setter method.





반응형