@Autowried入門和源碼分析


話不多說直接上代碼:

聲明一個接口userDao:

package ioc.hello;

public interface UserDao {
    public void test();
}

2個實現類:

package ioc.hello;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component("userdao")
public class UserDaoImpl implements  UserDao {
    public void test() {
        System.out.println("userDaoImpl...");
    }
}
package ioc.hello;

import org.springframework.stereotype.Component;

@Component("userdao2")
public class UserDaoImpl2 implements  UserDao {
    public void test() {
        System.out.println("userDaoImpl2...");
    }
}

UserService類注入接口:

package ioc.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("userservice")
public class UserService {
    @Autowired
    private UserDao dao;
    public void test() {
        dao.test();
    }
}

測試類:

package ioc.hello;
import ioc.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestIOC {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(AppConfig.class);
        annotationConfigApplicationContext.refresh();
        UserService service = annotationConfigApplicationContext.getBean(UserService.class);
        service.test();
    }
}

我們直接運行以上代碼的話講道理是會報錯的,為什么呢?因為我們的UserDao接口有2個實現類,但是我們在注入的時候注入的是接口類型,而且注入的名稱是dao;
看效果吧!

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'ioc.hello.UserDao' available: expected single matching bean but found 2: userdao,userdao2
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:215)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1139)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1088)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581)
    ... 13 more

上面的報錯相信大家都很熟悉吧。

如果我們把注入的接口的名稱修改為userdao或者是userdao2的話就會不報錯了,當然我們也可以注入dao,但是在注入的時候我們需要做一下處理,可以在要注入的實現類加一個@Primary注解,也可以在注入的時候加一個@Qualifier(或者是Resource)注解,指定注入的對象,這個知識點此處不做介紹;

package ioc.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("userservice")
public class UserService {
    @Autowired
    private UserDao userdao;
    public void test() {
        userdao.test();
    }
}

運行結果:

userDaoImpl...

下面我們就此看以下Spring中的源碼吧!

首先不得不說,我們的@Autowired注入是在對象創建的時候一起注入的,換句話說就是比如我們上面的案例中,在UserService中注入接口,是在UserService對象創建的時候注入的,看下面的代碼,對象創建之前初始化環境的代碼太多,這里就不分析了:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
調用了doCreateBean方法;在此處打上條件斷點,當beanName.equals("userservice"),然后調用了populateBean方法;
// 調用doCreateBean 創建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//設置屬性,非常重要
populateBean(beanName, mbd, instanceWrapper);
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
getBeanPostProcessors()方法會得到所有的后置處理器,遍歷以后,當后置處理器為AutowriedAnnotationPoetProcessor的時候完成了@Autowried注入
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
         }
      }
   }
}
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
//findAutowiringMetadata方法會找到注入的所有類的屬性
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
   metadata.inject(bean, beanName, pvs);
}
private InjectionMetadata findAutowiringMetadata(String beanName, 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());
   //injectionMetadataCache可以理解為,是所有的bean,從所有的bean中得到service
   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 = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}
org.springframework.beans.factory.annotation.InjectionMetadata#inject
@Override
   protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
       //得到dao的屬性名稱
       Field field = (Field) this.member;
      Object value;
      if (this.cached) {
         value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      }
      else {
         DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
         desc.setContainingClass(bean.getClass());
         Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
         Assert.state(beanFactory != null, "No BeanFactory available");
         TypeConverter typeConverter = beanFactory.getTypeConverter();
         try {
             //得到注入的對象,resolveDependency方法看下面
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
         }
         synchronized (this) {
            if (!this.cached) {
               if (value != null || this.required) {
                  this.cachedFieldValue = desc;
                  registerDependentBeans(beanName, autowiredBeanNames);
                  if (autowiredBeanNames.size() == 1) {
                     String autowiredBeanName = autowiredBeanNames.iterator().next();
                     if (beanFactory.containsBean(autowiredBeanName) &&
                           beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                        this.cachedFieldValue = new ShortcutDependencyDescriptor(
                              desc, autowiredBeanName, field.getType());
                     }
                  }
               }
               else {
                  this.cachedFieldValue = null;
               }
               this.cached = true;
            }
         }
      }
      if (value != null) {
         ReflectionUtils.makeAccessible(field);
         //用field.set方法注入,把value注入到了bean里面
         field.set(bean, value);
      }
   }
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
if (result == null) {
   result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } Class<?> type = descriptor.getDependencyType(); Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } //從Spring工廠中得到該接口下所有的實現類的bean;這個方法最終是通過beanDefinitionNames得到的bean
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //如果接口有多個實現類的話就走這邊,要遍歷這些bean找到適合的對象返回
            if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(type, matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans).
                        return null; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { //如果接口只有一個實現類的話,就直接得到第一個實現類作為bean返回了 // We have exactly one match.
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }

以上代碼中:如果接口只有一個實現類的話就已經結束返回了,返回了接口的實現類,返回以后通過 field.set(bean, value);實現了注入;所以如果接口只有一個實現類的話,我們在注入接口的時候,屬性名稱可以隨便寫,他都可以注入成功;

下面就是有多個實現類的邏輯了;
我們來看下matchingBeans.size() > 1這段邏輯代碼,調用了determineAutowireCandidate(matchingBeans, descriptor);

org.springframework.beans.factory.support.DefaultListableBeanFactory#determineAutowireCandidate

 

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
        Class<?> requiredType = descriptor.getDependencyType();
        //次處就是上面提到的處理@Primary注解的地方啦
        String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
        if (primaryCandidate != null) {
            return primaryCandidate;
        }
        String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
        if (priorityCandidate != null) {
            return priorityCandidate;
        }
        // Fallback
        for (Map.Entry<String, Object> entry : candidates.entrySet()) {
            String candidateName = entry.getKey();
            Object beanInstance = entry.getValue();
       //主要看這個方法:matchesBeanName; descriptor.getDependencyName()得到的是service類里面注入的接口的名稱 if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } } return null; }

org.springframework.beans.factory.support.DefaultListableBeanFactory#matchesBeanName

根據注入的屬性的名稱和bean的name做對比,是否equals,如果是的話就直接返回這個bean了,如果不是的話報錯啦。
所以這個地方就解釋了我們上面報錯的問題了,注入了dao,會分別通過用userdao和userdao2和dao做字符串比較,如果兩個都滿足的話就會找不到bean,繼而就報錯,如果找到了就直接注入了找到的這個bean了。

 

protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
        return (candidateName != null &&
                (candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
    }

到此就結束了。。。

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM