@Autowired

前言

最近在使用@Async注解进行异步操作的时候时,想过一下@Async注解的原理,这种需要@Enable*注解开启作用的注解,原理应该是大同小异。之前已经分析过了@Scheluded注解了,本以为这次看@Async注解会很轻松,但是还遇到了很多问题。

我们知道在调用带有@Async的方法的时候,会将这个方法作为一个任务放入到线程池中执行。

如果我们想要自己配置线程池的属性,只需要实现AsyncConfigurer接口即可。

公司的底层框架已经把线程池相关配置配置在了一个Configuration类中了,显然,这个类会实现上述的接口。

@Configuration
public class ExecutorPoolConfig implements AsyncConfigurer { 

@Autowired
    Executor commonExecutor;

    /**
     * 配置@Async线程池,使用通用线程池配置
     */
    @Override
    public Executor getAsyncExecutor() {
        return commonExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncUncaughtExceptionHandler() {

            @Override
            public void handleUncaughtException(Throwable ex, Method method, Object... params) {
                LOGGER.error("异步线程执行任务{}异常: {}", method.getName(), ExceptionUtil.getStackTrace(ex));
            }

        };
    }

        @Bean
    public Executor commonExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(poolSize);
        executor.setMaxPoolSize(poolMaxSize);
        executor.setQueueCapacity(queueCapacity);
        // 开启线程任务的关闭等待
        executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
        // 默认使用beanName
        executor.setThreadNamePrefix("IYCCommonPool-");
        // rejection-policy:当pool已经达到max size的时候,由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new MyRejectedCallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

当我第一次看到

     @Autowired
    Executor commonExecutor;

就在想,如果我在自己的服务里面同样构造了一个Executor类型的Bean,到底这个@Autowired会注入哪个Bean呢?经过测试,是会注入到我们自己构造的Bean的。这也是我们期待的结果,我们在自己的服务里构造新的线程池的时候,肯定是希望使用的是我们的线程池,而不是默认的线程池。我们希望我们的配置可以覆盖默认的配置,然而也确实做到了。但是为什么会覆盖呢?

@Autowired注入原理

我们来看获取Bean实例的方法

AbstractAutowireCapableBeanFactory#doCreateBean

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
      //初始化Bean。使用相应的构造方法来初始化Bean对象
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}


		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
          //对Bean的一些属性进行注入,这行代码是今天分析的主要部分
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
              //这行代码之前已经分析过了
              //执行Bean指定的初始化方法,这块也会对Bean执行符合条件的BeanPostProcessor,著名的Spring AOP思想就是在这块代码中实现的
              
				exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
		}
      
      
    }

populateBean

	protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
		PropertyValues pvs = mbd.getPropertyValues();

		if (hasInstAwareBpps || needsDepCheck) {
			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;
						}
					}
				}
			}
	
		applyPropertyValues(beanName, mbd, bw, pvs);
	}

这个方法的名字叫填充Bean,处理属性注入也是在这个方法中完成的,这个方法中很长,我们只关注我们要分析的部分,ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		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;
	}

选择合适的注入方式来完成属性注入的工作,Spring的流程实在是太多了,不一一分析了,有兴趣的可以Debug跟着跑一遍,我这里就不纠结这些细节了。

最后沿着执行链会执行到DefaultListableBeanFactory#doResolveDependency

	public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
			Set<String> autowiredBeanNames, 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;
			}
//寻找候选者,如果该Filed上不仅有@Autowired注解,还有@Qualifier注解,那么候选者最多只会有一个了
			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;
	//如果有多个候选者,那么需要选择最合适的候选者
			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 {
				// 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);
			}
			return (instanceCandidate instanceof Class ?
					descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

通过Field的类型和Field上的注解信息来获取合适的候选者

1.寻找候选者,通过findAutowireCandidates(beanName, type, descriptor);寻找Spring环境中类型与type相同的Bean,如果Field上还有@Qualifier注解,那么最多只可能有一个候选者(Spring中同名Bean默认会被覆盖,所以最多只能有一个候选者)。如果没有该注解,那么这里获取到的matchingBeans就可能是多个了。

	protected Map<String, Object> findAutowireCandidates(
			String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
		for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = this.resolvableDependencies.get(autowiringType);
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		
		for (String candidate : candidateNames) {
			//这里先会把不是把不是和当前Bean直接相关的候选者加入到CandidateEntry
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		if (result.isEmpty() && !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)) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
			//当没有和当前Bean不直接相关的候选者时
			if (result.isEmpty()) {
				// Consider self references as a final pass...
				// but in the case of a dependency collection, not the very same bean itself.
				//就需要选择和当前Bean在同一个FacoryBean的候选者中加入到CandidateEntry
				for (String candidate : candidateNames) {
					if (isSelfReference(beanName, candidate) &&
							(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
                        //当有@Qualifier注解存在时,这个方法会去判断是否是和@Qualifier注解里的值匹配的候选者,是的话,才加入
							isAutowireCandidate(candidate, fallbackDescriptor)) {
						addCandidateEntry(result, candidate, descriptor, requiredType);
					}
				}
			}
		}
		return result;
	}
private boolean isSelfReference(String beanName, String candidateName) {

		return (beanName != null && candidateName != null &&
		//如果候选者和当前Bean的名字相同                或者               
				(beanName.equals(candidateName) || 
				//候选者在当前Map of bean definition objects中
				(containsBeanDefinition(candidateName) &&
//并候选者的FactoryBean的名称和当前BeanDe名称相同时,返回true
                 beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName()))));
	}

那么在什么时候候选者的FactoryBean会是当前Bean呢?在使用注解代替传统的XML配置来配置Bean的时候,会将在配置类中的Bean的FactoryBean设置为他所在的配置类。

在Spring中,当在处理Bean的属性的注入的时候,当有候选者是配置在当前Bean这个类里面的时候,他的优先级是最低的。也就是说最开始的的commonExecutor这个Executor类型的Bean的优先级是最低的,只要有任意一个在其他的类里面配置的Executor类型的Bean,都会覆盖掉这个在ExecutorPoolConfig中配置的Bean。到这里已经解决了文初的疑问,但是还存在一种情况,那就是如果在其他的类中有多个该类型的Bean,那我们会选择哪个呢?

2.如果我们获取到了多个matchingBeans,那么我们需要选出优先级最高的那个类,通过determineAutowireCandidate(matchingBeans, descriptor);来选取最合适的Bean。

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
		Class<?> requiredType = descriptor.getDependencyType();
  //先看有没有候选者带有@Primary注解
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if (primaryCandidate != null) {
			return primaryCandidate;
		}
  //再看有没有优先级之分
  //当beanInstance是Class类型时,查看是否有```javax.annotation.Priority```类型的注解
  //否则看是否有javax.annotation.Priority类型注解,如果没有,那么再看是否有org.springframework.core.annotation.Order类型的注解.
  //那什么时候beanInstance会是
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if (priorityCandidate != null) {
			return priorityCandidate;
		}
		// Fallback
  //如果都没有,那么就看有没有候选者的Name和属性名相同
		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;
			}
		}
  //如果也没有的话,那么就返回null
		return null;
	}

一旦该方法返回null的时候,就会导致整个方法返回null或者是直接抛出异常。

	if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
      //一旦返回为null的时候,就会导致方法直接返回了
				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;
					}
				}
			}

所以当其他类中有多个Executor类型的Bean时:
1.看这些Bean有没有带有@Primary注解的,有的话就取这个。
2.再看有没有带有Order注解或者Priority,有的话就遍历所有的候选者,返回优先级最高的候选者。
3.最后在看下是否有候选者的BeanName和Field名相同,如果有,则返回匹配的候选者。

4.如果都没找到合适的候选者的话,返回null,抛出异常。

总结

当Spring环境中拥有多个相同类型的Bean时,在使用@AutoWired注解去引用的时候,是需要注意的。

  • 最好是使用@Qualifier去指定想要使用的Bean
  • 退而求其次的方法,就是在某个Bean上加上@Primary注解,指定这个Bean是优先级最高的Bean,在使用@AutoWired注解去引用这一类型的Bean的时候,优先取这个,也可以在Bean上加上@Order注解或者@Priority表名Bean的优先级,实在不行也要有一个Bean的名字与使用@AutoWired注解的Field或Method的Name相同,否则就要报错了。
  • 当Spring环境中有多个相同类型的Bean的时候,如果使用@AutoWired注解的Field或Method恰好和其中的一个Bean是同一个FactoryBean,那么这个Bean的匹配优先级是最低的,这一特性可以用来覆盖某些默认的配置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值