前言
上篇简述了 Spring 如何实例化 Bean,在实例化 Bean 之后还能干嘛,当然是属性注入,这篇分析一下 Spring 如何对属性自动装配。
代码
A.java
package com.playwin.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class A {
@Autowired
private B b;
@Value("Playwi0")
private String name;
}
B.java
package com.playwin.bean;
import org.springframework.stereotype.Component;
@Component
public class B {
}
doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// 删除代码
....
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
// 删除代码
....
}
// 删除代码
....
return exposedObject;
}
上篇说过,instanceWrapper = createBeanInstance(beanName, mbd, args);
之后,会返回一个实例化对象,但这个对象并不是一个完整的 Bean,Spring 在这之后调用 populateBean 方法完成属性注入。
populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 删除代码
....
// 配置文件
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// byName,byType 注入模型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
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;
}
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;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 删除代码
....
pvs = pvsToUse;
}
}
}
// 删除代码
....
}
在这里会判断注入模型,是 byName 还是 byType,很明显前面是使用注解配置,不存在 byName 还是 byType 注入模型,也就是说 @Autowired 注解和 byName, byType 没啥关系,也并不是某些博客说的那样,@Autowired 注解是根据byName 或 byType 注入。
继续走到下面逻辑,调用 Bean 后置处理器的 postProcessProperties 方法。那调用的是哪个后置处理器;一看便知。
AutowiredAnnotationBeanPostProcessor 很明显,这个后置处理器的名字已经暴露它是处理 @Autowired 注解。究竟是不是看看才知道。
postProcessProperties
@Override
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 这个方法已经很明,查找 @Autowired 注解数据,放到缓存,调用了metadata.inject(bean, beanName, pvs);
inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 所有自动装配属性
Collection<InjectedElement> checkedElements = this.checkedElements;
// 迭代器
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 遍历装配
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
拿到所有需要注入属性后,使用迭代器遍历,
进入了element.inject(target, beanName, pvs);
inject(AutowiredFieldElement)
这里面分为注解添加到了属性上面,和方法上面两种逻辑。先看属性
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
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 {
// 得到自动装配属性的值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// 如果这个自动装配属性也是 Spring 的 Bean,把它加入依赖缓存
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;
}
}
}
// 属性 set 注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
这里会得到属性的值,先不管怎么得到,最后你会看到,属性注入仅仅是调用field.set(bean, value);
这么简单代码来完成。
resolveDependency
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 删除代码
....
if (Optional.class == descriptor.getDependencyType()) {
// 删除代码
....
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
调用 doResolveDependency 方法
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();
// 如果有 @value 注解的值,找出 @value 注解的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// 如果值 @value 注解的值是 String 类型
// 如果是表达式,这里会执行表达式,value 变量会变成保存表达式结果值
// 如果不是表达式,会根据属性的类型给属性赋值。
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()));
}
}
// 属性可以储存多个,集合或数组
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 如果前面两种都不是,那么只剩下 @Autowired 注解
// 根据属性类型找出所有候选 Bean 的 Map 集合
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
// 对应的上面找出 Map 集合的 key,value
String autowiredBeanName;
Object instanceCandidate;
// 如果有多个,需要在此筛选
if (matchingBeans.size() > 1) {
// 在上面根据属性类型找出的 Map 集合里,再根据属性名字从里面找一遍。
// 这里也会解析 @primary 注解
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
// 没找到,除非类型是集合,可以为空,或者设置 required 值,否则报错
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
// 找到这个唯一的 Bean,就取出
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);
}
if (instanceCandidate instanceof Class) {
// 如果是个类,就实例化,里面是调用 getBean
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
// 没有实例化出 Bean???
// 应该不会进这里
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);
}
}
@value 注解会判断是否为表达式,比如配置文件里的属性。终于知道为什么有的文章会说 @Autowired 是 byType 或 byName 注入。这里,Spring 会按自动装配属性的类型找出所有符合的 Bean,如果有多个,再从结果里面按属性名字查找(这样的查找,并没有判断 byType 或 byName),如果没找到,并且没设置@Autowired(required = false)
或者属性不是可以存储多个元素类型,则会报错。最后找到的值是类就实例化instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
不信咱们测试一下。
一个接口两个实现类。
I.java
package com.playwin.bean;
import org.springframework.stereotype.Component;
@Component
public interface I {
}
IA.java
package com.playwin.bean;
import org.springframework.stereotype.Component;
@Component
public class IA implements I{
}
IB.java
package com.playwin.bean;
import org.springframework.stereotype.Component;
@Component
public class IB implements I{
}
在一个 Bean 设置注入属性。
B.java
package com.playwin.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class B {
@Autowired
I a;
}
注意属性类型和名字。按照上面所说,这里会按类型找出两个 Bean,但按名字找不到,报错。
按类型找到两个
按名字没有。
报错。
inject(AutowiredMethodElement)
上面是属性的,@Autowired 注解也是支持添加到方法上的。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (checkPropertySkipping(pvs)) {
return;
}
// 获取方法名字
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
}
else {
// 获取该方法参数个数
int argumentCount = method.getParameterCount();
arguments = new Object[argumentCount];
// 虽说是方法注入,但 Spring 在这里转换为了和属性一样的逻辑
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
// 反射 invoke
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
基本一模一样,这是提取出方法中参数,去解析出结果,然后反射执行方法。这里并限制什么方法,也就是说 @Autowired 注解添加到方法上会执行?
package com.playwin.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class A {
@Value("Playwi0")
private String name;
@Autowired
public void sout(){
System.out.println("惡搞");
}
}
可以是可以,但 Spring 并不建议你这样使用,而且这样用没什么卵用。要想执行方法 Spring 也提供了注解方式。
总结
看了这篇,你应该不会单纯的以为 @Autowired 注解是先 byType 再 byName 注入。 @Autowired 和注入模型没有任何关系,严格的说。