@Autowired註解的實現原理

掃描下方二維碼或者微信搜索公衆號菜鳥飛呀飛,便可關注微信公衆號,閱讀更多Spring源碼分析和Java併發編程文章。java

微信公衆號

1. 問題

在平時工做中,只要是作Java開發,基本都離不開Spring框架,Spring的一大核心功能就是IOC,它能幫助咱們實現自動裝配,基本上天天咱們都會使用到@Autowired註解來爲咱們自動裝配屬性,那麼你知道Autowired註解的原理嗎?在閱讀本文以前,能夠先思考一下如下幾個問題。spring

  • @Autowired註解是如何實現自動裝配的?
  • 當爲類型爲A的Bean裝配類型爲B的屬性時,若是此時Spring容器中存在多個類型爲B的bean,此時Spring是如何處理的?
  • 自動裝配的模型是什麼?有哪幾種?和Autowired註解有什麼關聯?

2. Demo

先按照以下示例搭建一下本文的demo工程sql

  • pom依賴
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.8.RELEASE</version>
</dependency>
複製代碼
  • 配置類,在配置類中指定掃描哪些包下的文件
@Configuration
@ComponentScan("com.tiantang.study")
public class AppConfig {
}
複製代碼
  • 定義兩個service接口以及實現類,而後在OrderServiceImpl中爲其注入UserService的實現類
public interface UserService {
}
複製代碼
@Service
public class UserServiceImpl implements UserService {
}
複製代碼
public interface OrderService {

	void query();

}
複製代碼
@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	private UserService userService;

	public void query(){
		System.out.println(userService);
	}
}
複製代碼
  • 啓動類,在啓動類中經過調用getBean()方法獲取到OrderService類,而後調用query()方法,在query()方法中會打印注入的UserService對象
public class MainApplication {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		OrderService orderService = applicationContext.getBean(OrderService.class);
		orderService.query();
	}
}
複製代碼
  • 運行main()方法,最終會在query()方法中打印出UserService對象。

3. 實現原理:AutowiredAnnotationBeanPostProcessor

經過上面的demo咱們完成了對OrderServiceImpl的自動裝配,爲其屬性userService完成了賦值操做,那麼Spring是如何經過@Autowired來實現賦值的呢?咱們知道,Spring在容器啓動階段,會先實例化bean,而後再對bean進行初始化操做。在初始化階段,會經過調用Bean後置處理來完成對屬性的賦值等操做,那麼同理,要想實現@Autowired的功能,確定也是經過後置處理器來完成的。這個後置處理器就是AutowiredAnnotationBeanPostProcessor。接下來咱們就來看看這個類的源碼。編程

3.1 什麼時候被加入

  • 在分析AutowiredAnnotationBeanPostProcessor的工做原理以前,咱們須要先知道它是什麼時候被加入到Spring容器當中的。畢竟只有先將它放入到容器中了,才能讓它工做。
  • 當咱們調用AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class)啓動容器的時候,在構造方法中會調用到this()方法,在this()方法中最終會調用到registerAnnotationConfigProcessors()方法,在該方法中,Spring會向容器註冊7個Spring內置的Bean,其中就包括AutowiredAnnotationBeanPostProcessor。若是想詳細瞭解Spring容器的啓動過程,能夠參考筆者的另外一篇文章:Spring源碼系列之容器啓動流程
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) {

	// 省略部分代碼...
	
	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
	// 註冊AutowiredAnnotationBeanPostProcessor,這個bean的後置處理器用來處理@Autowired的注入
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// 註冊CommonAnnotationBeanPostProcessor,用來處理如@Resource等符合JSR-250規範的註解
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	return beanDefs;
}
複製代碼

3.2 什麼時候被調用

AutowiredAnnotationBeanPostProcessor是什麼時候被調用的呢?數組

  • Spring在建立bean的過程當中,最終會調用到doCreateBean()方法,在doCreateBean()方法中會調用populateBean()方法,來爲bean進行屬性填充,完成自動裝配等工做。populateBean()方法的部分源碼以下。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	if (hasInstAwareBpps || needsDepCheck) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		if (hasInstAwareBpps) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 執行後置處理器,填充屬性,完成自動裝配
					// 在這裏會調用到AutowiredAnnotationBeanPostProcessor
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvs == null) {
						return;
					}
				}
			}
		}
	}
}
複製代碼
  • 在populateBean()方法中一共調用了兩次後置處理器,第一次是爲了判斷是否須要屬性填充,若是不須要進行屬性填充,那麼就會直接進行return,若是須要進行屬性填充,那麼方法就會繼續向下執行,後面會進行第二次後置處理器的調用,這個時候,就會調用到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues()方法,在該方法中就會進行@Autowired註解的解析,而後實現自動裝配。(注意:上面的源碼中,只貼出了執行一次後置處理器的代碼,另一次被省略了)。
  • postProcessorPropertyValues()方法的源碼以下,在該方法中,會先調用findAutowiringMetadata()方法解析出bean中帶有@Autowired註解、@Inject和@Value註解的屬性和方法。而後調用metadata.inject()方法,進行屬性填充。
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
	// 解析出bean中帶有@Autowired註解、@Inject和@Value註解的屬性和方法
	// 對於本文的demo而言,在此處就會解析出OrderServiceImpl類上的userService屬性
	// 至於如何解析的,findAutowiringMetadata()方法比較複雜,這裏就不展開了,Spring中提供了不少對註解等元數據信息讀取的方法,進行了大量的封裝。
	// 若是不是本身親自參與開發Spring的話,很難摸透它封裝的那些數據結構。
	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;
}
複製代碼

3.2.1 findAutowiringMetadata()

  • 爲何上面分析時,只說了findAutowiringMetadata()方法會解析出Autowired註解、@Inject和@Value註解呢?這是由於在AutowiredAnnotationBeanPostProcessor中定義了這樣一個全局變量:
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
複製代碼
  • 這個全局變量在AutowiredAnnotationBeanPostProcessor的構造方法中進行了初始化。初始化時,只向這個set集合中添加了三個元素:@Autowired、@Inject、@Value。其中@Inject註解是JSR-330規範中的註解。當調用findAutowiringMetadata()方法時,會根據autowiredAnnotationTypes這個全局變量中的元素類型來進行註解的解析,所以上面只說了findAutowiringMetadata()方法會解析出Autowired註解、@Inject和@Value註解這三個註解。
public AutowiredAnnotationBeanPostProcessor() {
	// 添加@Autowired
	this.autowiredAnnotationTypes.add(Autowired.class);
	// 添加@Value
	this.autowiredAnnotationTypes.add(Value.class);
	try {
		// 若是項目中引入了JSR-330相關的jar包,那麼就會添加@Inject
		this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
				ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
	}
	catch (ClassNotFoundException ex) {
		
	}
}
複製代碼

3.2.2 metadata.inject()

  • 對於屬性上加了Autowired註解的,通過上一步解析後,會將字段解析爲AutowiredFieldElement類型;若是是方法上加了Autowired註解,則會解析爲AutowiredMethodElement類型。它們均是InjectedElement類的子類,裏面封裝了屬性名,屬性類型等信息。對於@Resource,@LookUp等註解被解析後,也會解析成對應的InjectedElement的子類:ResourceElement、LookUpElement,可是這兩個註解是在其餘後置處理器中被解析出來的,並非在AutowiredAnnotationBeanPostProcessor中解析的。
  • metadata.inject()方法最終會調用InjectedElement類的inject()方法。對於本文中的demo,此時userService屬性被解析後對應的InjectedElement是AutowiredFieldElement類,因此在此時會調用AutowiredFieldElement.inject()方法。
  • 下面是AutowiredFieldElement.inject()方法的源碼。在源碼中加了部分註釋,從源碼中能夠發現,核心代碼是beanFactory.resolveDependency()
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Field field = (Field) this.member;
		Object value;
		// 判斷緩存(第一次注入userService的時候,確定沒有緩存,因此會進入到else裏面)
		// 當第一次注入完成後,會將userService緩存到cachedFieldValue這個屬性中,
		// 這樣當其餘的類一樣須要注入userService時,就會從這兒的緩存當中讀取了。
		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);
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {
				// 經過beanFactory.resolveDependency()方法,來從容器中找到userService屬性對應的值。
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			// 省略部分代碼...
			// 省略的這部分代碼就是將value進行緩存,緩存到cachedFieldValue屬性中
		}
		if (value != null) {
			// 經過Java的反射,爲屬性進行復制
			ReflectionUtils.makeAccessible(field);
			field.set(bean, value);
		}
	}
}
複製代碼
  • 在beanFactory.resolveDependency()方法中主要調用了doResolveDependency()方法,下面咱們重點分析一下doResolveDependency()這個方法,這個方法的代碼很長。源碼以下:
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;
		}
		// 省略部分不重要的代碼...
		
		// 屬性的類型多是數組、集合、Map類型,因此這一步是處理數組類型、Collection、Map類型的屬性
		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if (multipleBeans != null) {
			return multipleBeans;
		}
		// 根據須要注入的類型type,從容器中找到有哪些匹配的Bean。
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		// 若是從容器中沒有找到,且@Autowired的required屬性爲true,那麼則會拋出異常
		if (matchingBeans.isEmpty()) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;

		// 先根據類型匹配出能夠依賴注入的bean的Class,若是匹配出多個,則再根據屬性名匹配
		if (matchingBeans.size() > 1) {
			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					// 當匹配到多個bean的Class,可是殊不知道要選擇哪個注入時,就會拋出異常
					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 {
			// 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);
		}
		// 此處instanceCandidate = UserServiceImpl.class
		if (instanceCandidate instanceof Class) {
			// instanceCandidate是注入屬性的類型,這個須要根據Class,經過FactoryBean的getBean()方法,建立該類型的單例bean
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		if (result instanceof NullBean) {
			// 若是沒從容器中找到對應的bean,則須要判斷屬性值是不是必須注入的,
			// 即@Autowired(required=false/true),若是爲true,則拋異常,這就是常常項目啓動時,咱們看到的異常
			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);
	}
}
複製代碼
  • 在上面的源碼中,咱們看到調用了resolveMultipleBeans(),這個方法是爲了處理屬性時數組、集合、Map的狀況的,例如咱們在OrderServiceImpl中進行以下注入:
@Autowired
private UserService[] userServiceArray;

@Autowired
private List<UserService> userServiceList;

@Autowired
private Map<String,UserService> userServiceMap;
複製代碼
  • 這個時候,resolveMultipleBeans()方法就會從容器中找到全部的UserService類型的Bean。resolveMultipleBeans()方法中會調用findAutowireCandidate()方法,從容器中找到對應類型的bean,實際上最終會調用getBean()方法,這樣當UserService類型的對象還沒被建立時,就會去建立。(Spring中不管是建立Bean仍是獲取Bean,入口都是getBean()方法,若是須要詳細瞭解該方法,能夠閱讀比這的另外一篇文章:經過源碼看Bean的建立過程)。
  • resolveMultipleBeans()方法的部分源碼
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
	Class<?> type = descriptor.getDependencyType();
    // 處理數組類型
	if (type.isArray()) {
        // findAutowireCandidates最終會調用getBean()方法
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
				new MultiElementDescriptor(descriptor));
		return result;
	}
    // 處理集合類型
	else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
        // findAutowireCandidates最終會調用getBean()方法
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
				new MultiElementDescriptor(descriptor));
		return result;
	}
    // 處理Map類型
	else if (Map.class == type) {
        // findAutowireCandidates最終會調用getBean()方法
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
				new MultiElementDescriptor(descriptor));
		return matchingBeans;
	}
	else {
		return null;
	}
}
複製代碼
  • 若是須要注入的屬性是普通類型(非數組、集合、Map),那麼方法會繼續向下執行,會調用下面一行代碼,根據屬性的類型來查找bean。
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
複製代碼
  • 能夠看到又是調用findAutowireCandidates()方法,該方法最終會調用getBean()方法,因此它會從容器中找到對應類型的bean,即UserService類型的Bean。若是容器沒有找到對應類型的Bean,且屬性是必須注入的,即Autowired註解的required屬性爲true,那麼就會拋出異常,這個異常就是咱們常常看見的:NoSuchBeanDefinitionException
// 若是容器彙總沒有找到指定類型的bean,那麼matchingBeans屬性就是空的
if (matchingBeans.isEmpty()) {
	if (isRequired(descriptor)) {
        // 拋出異常
		raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
	}
	return null;
}
複製代碼
  • matchingBeans這個map的大小可能大於1,由於從容器中找到了多個知足類型的Bean,便可能找到多個UserService類型的bean,那麼這個時候就須要判斷這多個bean中,究竟應該注入哪個。
if (matchingBeans.size() > 1) {
    // 判斷應該使用哪個bean
	autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
	if (autowiredBeanName == null) {
		if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
			// 當匹配到多個bean的Class,可是殊不知道要選擇哪個注入時,就會拋出異常
			return descriptor.resolveNotUnique(type, matchingBeans);
		}
		else {
			return null;
		}
	}
	instanceCandidate = matchingBeans.get(autowiredBeanName);
}
複製代碼
  • 在上面的代碼中,會調用determineAutowireCandidate()方法,判斷應該使用哪個bean。若是determineAutowireCandidate()方法也沒法決定使用哪個,determineAutowireCandidate()就會返回null。這個時候若是屬性又是必須注入的,即@Autowired的required=true,那麼就會拋出異常(由於required=true表示這個屬性是必須注入的,可是程序又不知道須要注入哪個,因此就會出錯),這個異常也是咱們常常見到的:NoUniqueBeanDefinitionException
"expected single matching bean but found " + beanNamesFound.size() + ": " + StringUtils.collectionToCommaDelimitedString(beanNamesFound)
複製代碼
  • 那麼determineAutowireCandidate()又是如何判斷應該決定使用哪個bean的呢?Spring會先找到加了@Primary註解的bean,好比Spring找到了兩個UserService類型的Bean,分別爲UserServiceImpl1和UserServiceImpl2,若是UserServiceImpl1的類上加了@Primary註解,那麼就會優先使用userServiceImpl1類型的Bean進行注入。若是都沒有加@Primary註解,那麼就會找加了@Priority註解的bean,優先級最高的會被優先選中。若是都沒有加@Priority,那麼就會根據屬性的名稱和Spring中beanName來判斷,例如:UserServiceImpl1和UserServiceImpl2在Spring容器中beanName分別是userServiceImpl1和userServiceImpl2。若是此時OrderServiceImpl中須要注入的UserService類型的屬性名是userServiceImpl1,那麼Spring就會爲其注入UserServiceImpl1類型的單例對象;若是屬性名是userServiceImpl2,那麼Spring就會爲其注入UserServiceImpl2。若是屬性名與userServiceImpl1不相等,也與userServiceImpl2不相等,那麼就會返回null,那麼在方法的調用處,就會拋出NoUniqueBeanDefinitionException異常。
  • 這就是咱們日常所說的@Autowired註解是先根據類型注入,當碰到多個相同類型時,就會根據屬性名注入。它的實現原理就是在以下代碼中實現的。
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
	Class<?> requiredType = descriptor.getDependencyType();
	// 根據Primary註解來決定優先注入哪一個bean
	String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
	if (primaryCandidate != null) {
		return primaryCandidate;
	}
	// 根據@Priority註解的優先級來決定注入哪一個bean
	String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
	if (priorityCandidate != null) {
		return priorityCandidate;
	}
	// 若是既沒有指定@Primary,也沒有指定@Priority,那麼就會根據屬性的名稱來決定注入哪一個bean
	// 若是要注入的屬性的名稱與Bean的beanName相同或者別名相同,那麼會就會優先注入這個Bean
	for (Map.Entry<String, Object> entry : candidates.entrySet()) {
		String candidateName = entry.getKey();
		Object beanInstance = entry.getValue();
		if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
				matchesBeanName(candidateName, descriptor.getDependencyName())) {
			return candidateName;
		}
	}
	// 前面三種狀況都沒有肯定要注入哪一個bean,那麼就返回null。當返回null時,那麼就會再調用該方法出拋出異常。
	return null;
}
複製代碼
  • 當matchingBeans大於1,且經過determineAutowireCandidate()方法確認了使用哪一個bean注入時,或者當matchingBeans=1時,後面就會根據肯定的beanName,來從容器中找到對應的Bean,而後將Bean返回,最後在AutowiredFeildElement.inject()方法中,經過反射進行注入,完成自動裝配。
  • 至此,AutowiredAnnotationBeanPostProcessor就經過postProcessPropertyValues()方法完成了自動裝配。以上就是@Autowired註解的實現原理。

4. 自動裝配的模型

在文章的開頭,我問了一個問題:自動裝配的模型是什麼?有哪幾種?和Autowired註解有什麼關聯?實際上這個問題,和今天的主角AutowiredAnnotationBeanPostProcessor沒有任何關係。可是爲何又把它放在這篇文章中提出來呢?這是由於@Autowired註解的實現原理和自動裝配模型極爲容易混淆。緩存

  • 在@Autowired的實現原理中,咱們提到了它會現根據類型來匹配,即byType,當類型匹配到多個時,會根據屬性名匹配,即byName。而自動裝配的模型有3種,即對應Autowire枚舉類中的枚舉類型值,枚舉類中的名字也是ByName,ByType,那麼這兩個地方的byName和byType的含義是同樣的嗎。(這裏說3種,實際上不是特別準確,由於從下面源碼中能夠看到,Autowire枚舉的值實際上對應AutowireCapableBeanFactory類中的常量值,而在AutowireCapableBeanFactory中常量值有5個:AUTOWIRE_NO、AUTOWIRE_BY_NAME、AUTOWIRE_BY_TYPE、AUTOWIRE_CONSTRUCTOR、AUTOWIRE_AUTODETECT,其中AUTOWIRE_AUTODETECT目前已經被捨棄了)。
public enum Autowire {

	NO(AutowireCapableBeanFactory.AUTOWIRE_NO),

	BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),

	BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
}
複製代碼
  • 首先能夠很明確的說,這二者的含義是徹底不同的。@Autowired註解中byName和byType能夠理解爲實現自動裝配的技術,是一種實現手段,是咱們開發本身理解定義的,在Spring中,Spring並無爲這種實現手段來命名。而Autowire枚舉中的值,則是Spring定義的,它是用來描述Bean的裝配模型的,是用來給BeanDefinition的autowireMode屬性來賦值的。Spring中默認BeanDefinition的autowireMode的值爲Autowire.NO。
  • 第二,Bean的注入模型能夠手動指定,而@Autowired的實現原理我的是無法作出修改的。例如經過XML配置bean時進行指定,以下示例:
<bean id="orderService" class="com.tiantang.study.service.impl.OrderServiceImpl" autowire="byName">
</bean>
複製代碼
  • 或者經過@Bean註解的屬性值指定
@Bean(autowire = Autowire.BY_NAME)
public OrderService orderService(){
	return new OrderServiceImpl();
}
複製代碼
  • 當咱們爲Bean指定了具體的裝配模型時,那麼這個Bean對應的BeanDefinition的autowiredMode屬性值將會是咱們指定的值,而再也不是Spring默認的Autowire.NO。
  • 那麼指定裝配模型有什麼用處呢?它會在populateBean()方法中發揮用處。前面咱們貼出的populateBean()方法的代碼中,省略了一部分很重要的代碼,如今咱們再貼出populateBean()相對完整的代碼:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	// 判斷bean的注入模型是byName,仍是byType。
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// 對於MyBatis而言,Mapper在實例化以後,會填充屬性,這個時候,須要找到MapperFactoryBean有哪些屬性須要填充
		// 在Mapper的BeanDefinition初始化時,默認添加了一個屬性,addToConfig
		// 在下面的if邏輯中,執行完autowireByType()方法後,會找出另外另個須要填充的屬性,分別是sqlSessionFactory和sqlSessionTemplate
		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}

	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	if (hasInstAwareBpps || needsDepCheck) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		if (hasInstAwareBpps) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 第六次執行後置處理器,填充屬性,完成自動裝配
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvs == null) {
						return;
					}
				}
			}
		}
		if (needsDepCheck) {
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
	}

	if (pvs != null) {
		// 實現經過byName或者byType類型的屬性注入
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}
複製代碼
  • 在上面的源碼中,咱們發現,在調用後置處理器自動裝配屬性以前,會先進行判斷bean的裝配模型是哪種,若是是AUTOWIRE_BY_NAME,那麼就會調用autowireByName()方法,在autowireByName()方法中,會先經過setter方法找到屬性,而後根據屬性名從容器中查找Bean,爲其屬性賦值;若是是AUTOWIRE_BY_TYPE,那麼就會調用autowireByType()方法,autowireByType()這個方法也是先根據setter方法查找屬性,而後再根據屬性的類型從容器中查找bean,爲其屬性賦值。
  • 注意上面提到了經過setter方法查找屬性,在查找時Spring會忽略調不少setter方法,例如屬性的類型是基本數據類型,包裝類型,Date,String,Class,Local等等,這些都會被Spring忽略。
// 判斷bean的注入模型是byName,仍是byType。
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
	MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
		autowireByName(beanName, mbd, bw, newPvs);
	}
	// 對於MyBatis而言,Mapper在實例化以後,會填充屬性,這個時候,須要找到MapperFactoryBean有哪些屬性須要填充
	// 在Mapper的BeanDefinition初始化時,默認添加了一個屬性,addToConfig
	// 在下面的if邏輯中,執行完autowireByType()方法後,會找出另外另個須要填充的屬性,分別是sqlSessionFactory和sqlSessionTemplate
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
		autowireByType(beanName, mbd, bw, newPvs);
	}
	pvs = newPvs;
}
複製代碼
  • Spring經過autowireByName()或者autowireByType()查到屬性和屬性對應的Bean值之後,會將屬性和屬性值放到pvs這個局部變量中,而後在populateBean()方法的最後一行,調用了applyPropertyValues()方法,而後將其填充到Bean當中。
  • 從這兒也能夠發現,注入模型和Autowired註解的自動裝配技術沒有任何關聯關係。@Autowired須要藉助AutowiredAnnotationBeanPostProcessor類來實現裝配,而自動裝配模型則是定義bean的裝配類型是什麼,而後根據裝配類型來執行不一樣的方法,並不依賴於AutowiredAnnotationBeanPostProcessor類。
  • 對於自動裝配模型Autowire.BY_TYPE有一個經典的應用場景,那就是Spring和MyBatis的整合。在Spring和MyBatis整合時,每個Mapper最後對應一個MapperFactroyBean,而MapperFactroyBean的自動裝配模型就是AUTOWIRE_BY_TYPE。MapperFactroyBean在裝配時,會執行到autowireByType()方法,會根據setter方法找到符合條件的兩個屬性sqlSessionFactorysqlSessionTemplate,而後爲這兩個屬性賦值。
  • Spring整合MyBatis時,建立MapperFactoryBean的BeanDefinition的部分源代碼以下:
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
	GenericBeanDefinition definition;
	for (BeanDefinitionHolder holder : beanDefinitions) {
		definition = (GenericBeanDefinition) holder.getBeanDefinition();
        // 指定MapperFactoryBean的自動裝配模型爲AUTOWIRE_BY_TYPE 
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
	}
}
複製代碼
  • 綜上,自動裝配的模型中的ByName、ByType與@Autowired裝配的ByName、ByType不是同一個含義,二者徹底沒有關係。

5. 總結

總結以前,先回答一下文章開頭的三個問題。1)@Autowired註解的實現是經過後置處理器AutowiredAnnotationBeanPostProcessor類的postProcessPropertyValues()方法實現的。2)當自動裝配時,從容器中若是發現有多個同類型的屬性時,@Autowired註解會先根據類型判斷,而後根據@Primary、@Priority註解判斷,最後根據屬性名與beanName是否相等來判斷,若是仍是不能決定注入哪個bean時,就會拋出NoUniqueBeanDefinitionException異常。3)@Autowired自動裝配中byName、byType與自動裝配的模型中的byName、byTYpe沒有任何關係,二者含義徹底不同,前者是實現技術的手段,後者是用來定義BeanDefiniton中autowireMode屬性的值的類型。微信

  • 本文經過源碼主要分析了@Autowired註解的實現原理是經過AutowiredAnnotationBeanPostProcessor這個後置處理器來實現的,而後針對@Autowired注入過程當中若是碰到多個同類型的bean時該如何處理的實現細節作了具體的分析。
  • 經過本文咱們不只知道了@Autowired註解的實現原理,還知道了@Autowired註解還能爲咱們注入Map、數組、Collection類型的屬性。
  • 接着本文經過Spring中自動裝配的模型,比較了自動裝配模型與@Autowired的關聯關係,並經過舉例Spring與MyBatis整合的例子,介紹了自動裝配模型BY_TYPE的使用場景,並作了簡單分析。
  • 最後,看完本文,你能猜到@Resource註解的實現原理嗎?若是還不清楚的話,能夠看下CommonAnnotationBeanPostProcessor類的源碼。

相關推薦數據結構

相關文章
相關標籤/搜索