一、如何手動設(shè)置注入模型
Spring的注入模型屬于beanDefifinition的一個屬性(默認(rèn)為0),可以手動設(shè)置
xml設(shè)置
<bean id="n" class="xxxx" autowire="byType"> </bean>
JAVA代碼設(shè)置
public class ModelBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("bean"); //獲取注入模型
//手動設(shè)置注入模型
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
二、Spring的四種注入模型
public interface AutowireCapableBeanFactory extends BeanFactory {
/**
* Constant that indicates no externally defined autowiring. Note that
* BeanFactoryAware etc and annotation-driven injection will still be Applied.
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
/**
* 默認(rèn)的裝配模式,如果注入indexBean,沒有在屬性上加@Autowired或者@Resource,這時候,indexBean是無法注入的
*/
int AUTOWIRE_NO = 0;
/**
* Constant that indicates autowiring bean properties by name
* (applying to all bean property setters).
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
/**
* 通過屬性名自動裝配。Spring尋找與需要自動連接的屬性同名的bean。
* 例如,如果一個bean定義按名稱設(shè)置為自動裝配,并且它包含一個master屬性(也就是說,它有一個setMaster(…)方法),
* Spring就會查找一個名為master的bean定義,并使用它來設(shè)置屬性。
*/
int AUTOWIRE_BY_NAME = 1;
/**
* Constant that indicates autowiring bean properties by type
* (applying to all bean property setters).
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
/**
* 如果容器中恰好存在該屬性類型的一個bean,則自動連接該屬性。
* 如果存在多個,將拋出一個致命異常,這表明您不能對該bean使用byType自動裝配。
* 如果沒有匹配的bean,則什么也不會發(fā)生(屬性沒有設(shè)置)。
*/
int AUTOWIRE_BY_TYPE = 2;
/**
* Constant that indicates autowiring the greediest constructor that
* can be satisfied (involves resolving the appropriate constructor).
* @see #createBean
* @see #autowire
*/
/**
* 類似于byType,但適用于構(gòu)造函數(shù)參數(shù)。
* 如果容器中沒有確切的構(gòu)造函數(shù)參數(shù)類型的bean,則會引發(fā)致命錯誤。
*/
int AUTOWIRE_CONSTRUCTOR = 3;
/**
* Constant that indicates determining an appropriate autowire strategy
* through introspection of the bean class.
* @see #createBean
* @see #autowire
* @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
* prefer annotation-based autowiring for clearer demarcation of autowiring needs.
*/
/**
* 通過bean的內(nèi)省來選擇合適的自動裝配策略(根據(jù)英文翻譯,就是spring會選擇最適合裝備的策略)
*/
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
}
三、Autowired注解注入源碼分析
注:此處只分析注入的核心流程,細(xì)節(jié)不在此展開
通過
AutowiredAnnotationBeanPostProcessor的postProcessProperties方法完成對@Autowired注解的處理和解析
這里最終會將所有打了Autowiring注解的字段和方法全部構(gòu)建成
InjectionMetadata.InjectedElement放入一個set集合中進(jìn)行處理
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
/**
* 遍歷類中的所有屬性字段
*/
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 查詢是否有 Autowired 注解
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 判斷注解中是否有 Required
boolean required = determineRequiredStatus(ann);
// 封裝成 AutowiredFieldElement 放入 currElements 集合
currElements.add(new AutowiredFieldElement(field, required));
}
});
/**
* 遍歷類中所有方法
*/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 查詢是否有 Autowired 注解
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
// 判斷注解中是否有 Required
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 封裝成 AutowiredMethodElement 放入 currElements 集合
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
之后在調(diào)用
org.springframework.beans.factory.annotation.InjectionMetadata#inject方法進(jìn)行屬性填充
其中
AutowiredAnnotationBeanPostProcessor類里面有3個內(nèi)部類,其中2個類為AutowiredFieldElement和AutowiredMethodElement,這2個類封裝了對打在字段上或者方法上的@Autowired注解進(jìn)行處理的邏輯;
我們就根據(jù)AutowiredFieldElement字段上的@Autowired注解進(jìn)行分析,這個也是我們最常用的方式;
入口方法為inject方法,就是上面InjectionMetadata遍歷調(diào)用的inject方法;
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
org.springframework.beans.factory.support.DefaultListableBeanFactory#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;
}
// 獲取依賴的類型
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());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
/**
* 解析當(dāng)前依賴是否支持多個bean注入,如:list、set、map類型等
* 如果支持多個bean注入,則在內(nèi)部就完成bean的查找,不為空直接返回
*/
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
/**
* 根據(jù)類型查詢bean實例,可能會有多個,key為需要注入對象的名字
*/
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// 判斷在依賴上面是否加了必須的條件,默認(rèn)為true
if (isRequired(descriptor)) {
// 拋出異常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
// 如果非必須則返回null,不注入任何對象
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果找出的實例大于1個
if (matchingBeans.size() > 1) {
// 通過依賴描述組件來推斷需要注入對象的名字
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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.
// 如果找出來的實例為1個,則直接獲取出來,賦值給instanceCandidate
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 判斷是否為Class,如果是則說明沒有實例化
if (instanceCandidate instanceof Class) {
// 實例化
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// 將獲取到的實例候選賦值給result
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);
}
}
四、Autowired分析總結(jié)
先根據(jù)類型查找bean;如果沒有找到則報錯(默認(rèn)情況下@Autowired是一定需要注入一個bean的);如果查找到一個則用找到的這一個完成注入;如果查找到多個,先把這個多個放到map當(dāng)中,繼而根據(jù)屬性的名字從map當(dāng)中去獲取;能獲取到則使用獲取的這個;如果map當(dāng)中通過名字還是無法獲取則報錯;
@Autowired不會改變bean的注入模型(默認(rèn)情況下bean的注入模型還是0);@Autowired算是一種半自動注入;因為他只需要程序員告訴spring需要注入的屬性或者方法,而不需要程序員告訴spring需要注入的屬性或者方法他的值到底是哪個bean;@Autowired會根據(jù)自己的規(guī)則去查找這個bean,所以只能算作半自動注入;
五、Resource注解注入源碼分析
通過
CommonAnnotationBeanPostProcessor這個類的postProcessorProperties方
法來完成對@Resource注解的解析和處理
后續(xù)的流程和Autowired差不多,就是掃描出來類所有加了Resource注解的屬性,封裝成對應(yīng)的
InjectionMetadata.InjectedElement
在封裝成ResourceElement時會讀取注解中的值進(jìn)行參數(shù)的賦值
在調(diào)用ResourceElement的inject方法進(jìn)行屬性注入,但我們發(fā)現(xiàn)ResourceElement沒有inject方法,我們就可以猜想出,這個方法肯定繼承至父類
我們最終在
InjectionMetadata.InjectedElement中找到了inject方法
在調(diào)用子類ResourceElement的getResourceToInject方法
判斷Resource是否自定義了名字,如果自定義了,則不會走類型查詢并注入,而是會走else因為自定義了名字說明我們想根據(jù)名字注入對象;
如果沒有自定義會先根據(jù)名字判斷是否在單例池中存在或者在beanDefinitionMap中存在,存在則通過名字獲取,沒有則在通過類型去獲取,獲取到一個則進(jìn)行注入,沒有獲取到或者獲取到多個則拋異常;
六、Resource分析總結(jié)
@Resource在沒有配置name的情況下首先根據(jù)名字查找;
如果名字能查找到則返回這個查找到的(spring容器的原則是name唯一的,所以不存在通過名字能查找到多個的情況);
如果通過名字查找不到(需要注意的是這里的前提是沒有配置name的情況,spring覺得名字無所謂);因為對名字無要求,所以會再根據(jù)類型查找;那么走的就是@Autowired這一套;
如果配置了名字,spring覺得對名字有嚴(yán)格要求,所以只能根據(jù)你配置的名字查找;如果查找不到則報錯,找到了則用;