两种:
手动:set(byType、byName)、构造器
自动:xml中:set、构造器 autowired注解中:set、属性、构造器
重点不在于到底有几种,而在于是否真的理解了依赖注入。
具体分析属性填充populateBean方法:只看关键部分,注入的部分
// 是否在BeanDefinition中设置了属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// by_name是根据根据属性名字找bean
// by_type是根据属性所对应的set方法的参数类型找bean
// 找到bean之后都要调用set方法进行注入
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
// 注意,执行完这里的代码之后,这是把属性以及找到的值存在了pvs里面,并没有完成反射赋值
}
// 执行完了Spring的自动注入之后,就开始解析@Autowired,这里叫做实例化回调
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 调用BeanPostProcessor分别解析@Autowired、@Resource、@Value,得到属性值
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
}
xml方式的byName和byType
简单说一下xml的byType和byName
Spring在通过byName的自动填充属性时流程是:
Spring在通过byType的自动填充属性时流程是:
然后进autowireByType方法看一下源码:resolveDependency 是一个核心方法,稍后在@Autowired处分析。beanDefinition方式解析不做过多分析
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set autowiredBeanNames = new LinkedHashSet<>(4);
// 找到有对应set方法的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
// set方法中的参数信息
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
// 当前Bean是否实现了PriorityOrdered
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 根据类型找bean,这就是byType
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
接下来分析@Autowired方式注入,重新回到填充属性方法populateBean中,看这一段BeanPostProcessor的postProcessProperties方法调用。
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//用于进行@Autowired和@Value、@Resource的注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
直至循环到AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取注入的元信息
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;
}
然后深入到findAutowiringMetadata()->buildAutowiringMetadata()方法中,看这一段源码:
// 遍历属性,看是否有@Autowired,@Value,@Inject注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 如果存在@Autowired,@Value,@Inject注解其中一个
MergedAnnotation> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 如果字段是static的,则直接进行返回,不进行注入
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,这个在属性填充前(MergedBeanDefinitionPostProcessor中)
//,此时只是告诉spring要注入这些,还没有真正注入。
//真正注入还是在属性填充内完成
currElements.add(new AutowiredFieldElement(field, required));
}
});
@Autowired为什么不支持静态的 ?
静态变量、类变量不是对象的属性,而是一个类的属性,所以静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法。而使用静态变量、类变量扩大了静态方法的使用范围。静态方法在spring是不推荐使用的,依赖注入的主要目的,是让容器去产生一个对象的实例,然后在整个生命周期中使用他们,同时也让testing工作更加容易。一旦你使用静态方法,就不再需要去产生这个类的实例,这会让testing变得更加困难,同时你也不能为一个给定的类,依靠注入方式去产生多个具有不同的依赖环境的实例,这种static field是隐含共享的,并且是一种global全局状态,spring同样不推荐这样去做。
然后进行进入findAutowiredAnnotation方法,该方法是为了获取是否有这些注解
private MergedAnnotation> findAutowiredAnnotation(AccessibleObject ao) {
// 查看当前字段上是否存在@Autowired,@Value,@Inject注解,存在其中一个则返回,表示可以注入
MergedAnnotations annotations = MergedAnnotations.from(ao);
// autowiredAnnotationTypes是一个LinkedHashSet,所以会按顺序去判断当前字段中是否有Autowired注解,如果有则返回
// 如果没有Autowired注解,那么则判断是否有Value注解,再判断是否有Inject注解
for (Class extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
为什么会只查看@Autowired,@Value,@Inject注解?
因为autowiredAnnotationTypes里只添加了这三个,为什么会先判断@Autowired,是因为是LinkedHashSet,按添加顺序去判断,看一下源码添加逻辑
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
//如果有这个类就添加,没有则跳过
this.autowiredAnnotationTypes.add((Class extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
我们返回到buildAutowiringMetadata()方法中:刚才是遍历了所有属性,接下来是遍历所有方法,本质上还是通过方法获取到了属性。
// 遍历方法,看是否有@Autowired,@Value,@Inject注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
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;
}
// 方法参数值为0,不能用来注入属性
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);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
findAutowiringMetadata()方法内的内容执行完毕,获取到注入点的元信息metadata,然后接下来将注入点注入进去。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取到注解的元信息metadata
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;
}
进入到inject方法中,这里是循环将InjectedElement进行注入。
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
再向里面走,进入inject方法,这时使用的是子类重写的inject方法,而不是自己的inject方法。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
// 当前注入点已经注入过了,有缓存了,则利用cachedFieldValue去找对应的bean
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// Spring在真正查找属性对应的对象之前, 会先将该属性的描述封装成一个DependencyDescriptor(依赖描述)对象,
// 里面保存了Filed、是否强制需要即required, 以及属性所在的类(即Field所在的类Class对象)
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 根据field去寻找合适的bean
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;
// 注册当前bean依赖了哪些其他的bean的name
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(bean, value);
}
}
如何根据field去寻找合适的bean,深入到的方法resolveDependency()里。该方法里前半部分主要为了判断依赖描述的类型,直接看后半段。
如Optional方法用get得到。ObjectFactory可用于注入每次都去getObject,如原型模式可以是不同对象。
else {
// 在使用@Autowired注解时,也可以使用@Lazy注解,到时候注入的会是一个代理对象
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 通过解析descriptor找到bean对象
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
具体解析还是在doResolveDependency()方法中,进去查看,这个方法内容比较多,我们来慢慢分析
一开始进行了缓存判断和@Value注解的解析
//依赖描述信息的缓存判断
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
//获取依赖描述的类
Class> type = descriptor.getDependencyType();
//获取该注入对象上的@Value注解,这也可以知道@Autowired和@Value是可以同时使用的
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
获取到@Value后进行判断是否存在,先分析存在的情况
if (value != null) {
if (value instanceof String) {
// 先进行占位符的填充,解析"$"符号,如@Value("${aa}")
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析Spring EL表达式,解析"#"符号(可以进行运算,可以写某个bean的名字)
value = evaluateBeanDefinitionString(strVal, bd);
}
再来分析不存在的情况,先判断了依赖描述的类型
// 要注入的依赖的类型是不是一个Map、Array、Collection,不是的话就继续走。
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
当不是以上三种类型的情况下,到下面调用了这个方法findAutowireCandidates(寻找注入的候选者),在resolveMultipleBeans方法中其实也是这个核心方法。
返回的map中的value是对象,可能是bean对象,也可能是class对象,因为该方法不负责实例化。
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
接下来分析一下findAutowireCandidates这个方法。
//去当前beanfactory以及祖先beanfactory中找类型为requiredType的bean的名字,将找到的name作为候选者记录下来
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map result = new LinkedHashMap<>(candidateNames.length);
//把resolvableDependencies中保存的对象作为当前属性的一个候选者? ------这段代码不是太理解
for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
//对候选者进行过滤,
//两个判断,第一个判断是否是自己的引用
//第二个判断为是否能被注入,里面包含了对@Qualifier注解的判断,如果有@Qualifier,则确认@Qualifier的name与descriptor的是否一致
//如:@Autowired
//@Qualifier("order")
//public Order order22;
//就会注入一个beanName为order,调用为order22的bean。
//只使用@Autowired的话会寻找到type为order的bean,如果只有一个bean,那么正确返回,如果有多个则抛出异常
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
//如果已经有候选者则直接返回,没有则进行下面流程
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
//如果第一次传递找不到任何内容,请考虑回退匹配。。。
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// 如果还是没有,则放宽要求,允许自己注入自己,但不是同一个bean
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
然后返回了候选者列表,如果不存在就去判断required是否为true,为true则报错,为false直接返回null
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
接着开始判断候选者的个数,如果只有一个,则返回,多个进行进一步的处理。
先来分析简单的,一个的情况,会执行下面代码
else {
// 只有一个
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
接下来就是将获得的autowiredBeanName和instanceCandidate进行一些判断,不一一列举了。找个典型的:
//来判断获取的这个对象是bean还是class对象,如果是class对象则调用getBean方法
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
然后回到候选者数量判断那里,如果是多个的情况:会调用determineAutowireCandidate方法
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
进入determineAutowireCandidate方法,里面进行了@Primary和@Priority注解的判断,可以得知顺序为先判断@Primary,再判断@Priority
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
至此,resolveDependency方法的核心内容分析完毕,整个依赖注入的过程也分析完了,稍微总结一下。
依赖注入的流程:在bean实例化后进行属性填充,忽略xml配置的方式,只说@Autowired的过程。
1.通过InstantiationAwareBeanPostProcessor#postProcessProperties切入,进行@Autowired和@Value、@Resource的注入点的注入。
2.判断是否存在@Autowired,@Value,@Inject注解是否存在任意一个,存在就保存为注入点,以便之后的注入。
3.将注入点进行注入。
3.1 发现有@Value注解,则进行#和$的表达式的解析,返回相应bean。
3.2 进行注入,发现没有@Value注解,则寻找候选者。
4.寻找到所有符合的候选者,然后进行过滤
4.1如果有@Qualifier注解,则进行判断@Qualifier上的name与bean中的name是否一致,符合的通过筛选
5.筛选结束,进行候选个数判断
5.1.如果只有一个,则返回对应的bean
5.2.如果还有多个,则进一步的筛选
6.进行@Primary和@Priority注解的筛选
6.1.如果有一个@Primary注解,则返回对应的bean,多个报错。
6.2.如果没有@Primary注解,则进行@Priority注解的筛选,数字越小优先级越高,返回优先级最高的bean
7.通过反射就bean的值设置进来,完成注入。
(每次没找到bean,就会判断一下required)
题外话:如果是@Resource方式注入(j2ee的注解),有几种方式(针对同种type有多个的情况):
1.如果不写name,但存在对应的bean,则直接返回。
2.如果不写name,还不存在bean,则报错。
3.如果写了name,但不存在对应的bean,则会执行@Autowired的逻辑。
4.如果写了name,并存在对应的bean,则会直接通过byName去找。