Spring注解源码解析:@Autowired
流程:
经过我们的分析和推断,解析注解@Autowired的时机,其实就是在为bean实例填充属性的时候,会调用AutowiredAnnotationBeanPostProcessor中的方法postProcessProperties,为bean实例解析注解并填充属性信息。
我们以方法postProcessProperties为入口,看了下注解@Autowired是如何解析的,其实就是获取类中所有字段以及方法上的注解,注解包括@Autowired以及@Value;但是,添加了注解的字段或方法是不允许static关键字修饰的,而且,添加注解的方法也不允许是无参方法,否则字段的值无法注入。
最后,我们可以看到解析到的所有注解信息,最后都会被设置到相应的字段和方法中。
/ * @see AutowiredAnnotationBeanPostProcessor
* @see Qualifier
* @see Value
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
AutowiredAnnotationBeanPostProcessor是一个Bean的后处理器,前面我们在讲解后处理器时,已经了解过了,后处理器接口BeanPostProcessor中提供了两个方法,分别是方法postProcessBeforeInitialization以和方法postProcessAfterInitializatio
可惜的是,我们在AutowiredAnnotationBeanPostProcessor类中并没有找到这两个方法的具体实现,但是,却在它的父类InstantiationAwareBeanPostProcessorAdapter中,发现了这两个方法的实现。
可以看到,在InstantiationAwareBeanPostProcessorAdapter中这两个方法默认并没有什么逻辑,都是空实现,这就证明后处理器AutowiredAnnotationBeanPostProcessor的核心逻辑,并不是围绕着接口BeanPostProcessor中的两个方法展开的。
那我们就要到其他地方寻找线索了,可以看到,AutowiredAnnotationBeanPostProcessor类的继承体系中,继承接口BeanPostProcessor的还有接口InstantiationAwareBeanPostProcessor
postProcessProperties()
方法postProcessProperties是在为bean实例填充属性时被调用的
方法postProcessProperties的返回值类型为PropertyValues,也就是说当前是在解析属性的信息。
而前面我们在分析bean加载的逻辑时,有一个环节就是为刚实例化出来的bean填充属性,在属性信息填充之前,会将各种各样的属性信息封装到PropertyValues中,
@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中的逻辑并不算太复杂,首先获取cacheKey,如果beanName不为空,就以beanName为cacheKey,否则以类的全限定名为cacheKey。
尝试从缓存injectionMetadataCache中,根据cacheKey获取InjectionMetadata类型的metadata,InjectionMetadata根据名称,我们大致可以理解为是可以注入到bean实例中的注解元数据,里面封装了@Autowired对应属性或方法参数的值
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 首先获取cacheKey,如果beanName不为空,就以beanName为cacheKey,否则以类的全限定名为cacheKey。
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 尝试从缓存injectionMetadataCache中,根据cacheKey获取InjectionMetadata类型的metadata,InjectionMetadata根据名称,我们大致可以理解为是可以注入到bean实例中的注解元数据,里面封装了@Autowired对应属性或方法参数的值
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;
}
判断当前bean的类型是否符合条件
方法buildAutowiringMetadata中的第一段代码:
首先会通过AnnotationUtils中的方法isCandidateClass,判断当前bean实例的类clazz是否符合条件。
对类中的每个字段进行解析,可以看到会调用方法findAutowiredAnnotation,寻找字段上的注解,我们到方法findAutowiredAnnotation中看下
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
//首先会通过AnnotationUtils中的方法isCandidateClass,判断当前bean实例的类clazz是否符合条件。
//如果不存在指定类型的autowiredAnnotationTypes注解,则返回空的
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
//首先对类中的每个字段进行解析,可以看到会调用方法findAutowiredAnnotation,寻找字段上的注解,我们到方法findAutowiredAnnotation中看下
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
//判断字段是否被static关键字修饰了,如果是的话添加的注解将会失效,这也警示我们不能在静态属性中添加@Autowired或@Value。
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
//会调用方法determineRequiredStatus获取Required的值
boolean required = determineRequiredStatus(ann
//将类中所有字段解析到的注解信息,添加到集合currElements中。
currElements.add(new AutowiredFieldElement(field, required));
}
});
AutowiredAnnotationBeanPostProcessor初始化时,就会为成员变量this.autowiredAnnotationTypes添加一些初始化元素,而且,我们可以发现竟然就是我们的目标注解@Autowired,同时还包含了注解@Value。
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
这里会遍历this.autowiredAnnotationTypes中的每个注解,其实也就是注解@Autowired和注解@Value,如果发现字段中存在这这两个注解就返回它们,这些都是反射底层的API,
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
接下来就是要解析类中每个方法上的注解信息,其实解析的流程和步骤和前面解析字段上的流程是差不多的。
首先,从方法上获取注解信息,然后判断下方法是否是静态方法,这里也是不允许在静态方法上添加@Autowired和@Value的,然后获取属性required的值,最终设置到集合currElements中。
当然,和字段注解的解析不同的是,这里还额外判断了下方法的参数个数,如果参数个数为0也是不允许的,因为这样Spring就不知道你需要注入的值要设置到哪个属性上了。
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;
}
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));
}
});
给字段或方法注入属性的值
可以看到,接下来就是要把解析到的注解信息注入到相应属性pvs上,我们再到metadata的方法inject中看下:
在方法inject中,会遍历我们前面解析到的注解信息,然后调用element的方法inject。
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
//在方法inject中,会遍历我们前面解析到的注解信息,然后调用element的方法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);
}
}
}
如果注解是字段上的,那就给具体字段注入值;如果注解是方法上的,那就执行方法来注入参数的值,注解@Autowired和注解@Value底层自动注入的逻辑,也就是这样通过反射API来完成属性值的注入
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}