概念
@Autowired是一种注解,可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作,@Autowired标注可以放在成员变量上,也可以放在成员变量的set方法上,也可以放在任意方法上表示,自动执行当前方法,如果方法有参数,会在IOC容器中自动寻找同类型参数为其传值。
这里必须明确:@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier使用;
核心
我们先来看下实现的核心类 AutowiredAnnotationBeanPostProcessor 对应的类图,从中可以看到也是通过 BeanPostProcessor 来实现的。因为实现了 InstantiationAwareBeanPostProcessor 接口,所以在依赖注入的时候就会进行执行。
原理
在Spring 之 DI 详解讲解到的 AbstractAutowireCapableBeanFactory.populateBean() 方法这样一段代码,这里正是 @Autowried 注解进行解析执行的地方。
//对非autowiring的属性进行依赖注入处理
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;
//@Autowired、@Value、@Inject等注入注解就是在此处进入进行实现(AutowiredAnnotationBeanPostProcessor)
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) {
//获取bean的所有需要自动注入的属性和方法封装到InjectionMetadata的injectedElements集合里面
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;
}
我们先来看看是如何查找自动注入的属性和方法,
//初始化时就将@Autowried、@Value或javax.inject.Inject包下的注解添加到自动注入的类型中,以便后续使用扫描数据
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.
}
}
//寻找需要进行自动注入的数据
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
//构建需要进行自动装配的数据对象
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
//存储当前包含了自动装配注解的元素
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//获取包含自动装配注解的字段
AnnotationAttributes 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;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//获取包含自动装配注解的方法
AnnotationAttributes 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);
}
}
boolean required = determineRequiredStatus(ann);
//获取到方法的入参
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
//如果字段或方法没有注解则直接返回
if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
//如果配置了@Autowried、@Value或javax.inject.Inject包下的注解(如:@Inject等),则添加到要处理的注解数据集合中
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
if (attributes != null) {
return attributes;
}
}
}
return null;
}
从上面我们可以清楚看到,Spring 会查找到当前 Bean 所有配置了@Autowried、@Value或javax.inject.Inject包下的注解的属性或方法并将其添加到要处理的注解数据集合中。
这里有一点需要说明,其实这不是第一次加载这边注解数据,在 AbstractAutowireCapableBeanFactory.doCreateBean() 方法中调用 createBeanInstance 方法实例化数据后就会调用 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition() 方法进行解析对应的注解数据并缓存起来。第二次走到 findAutowiringMetadata 方法时,直接从缓存中获取即可。但在理解 @Autowried 原理上来说并不受影响。
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//获取bean的所有需要自动注入的属性和方法封装到InjectionMetadata的injectedElements集合里面
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
//判断是否外部管理的配置成员
metadata.checkConfigMembers(beanDefinition);
}
接下来看看是如何进行依赖注入的,跳转到 InjectionMetadata.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);
}
//调用AutowiredFieldElement.inject()从beanFactory中获取到对应属性bean进行依赖注入
//调用AutowiredMethodElement.inject()从beanFactory中获取到对应入参bean,并执行方法
element.inject(target, beanName, pvs);
}
}
}
后面都是通过 BeanName 从 BeanFactory 中获取到对应的 Bean 引用,然后通过反射注入属性或执行方法。有兴趣的同学可以自己进一步看看,这里就不再跟进了。
总结
在进行依赖注入的时候,进入到 AutowiredAnnotationBeanPostProcessor 类执行对应方法。将配置了@Autowried、@Value或javax.inject.Inject包下的注解的属性或方法封装成AutowiredFieldElement或者AutowiredMethodElement对象,最后统一把这些对象封装成InjectionMetadata对象。在后续遍历这些对象数据时,通过反射给属性赋值或调用方法。