@Autowired注解是否需要setter方法?

场景

我在研究为什么SpringBoot框架不推荐使用@Autowired注解的时候,突然想到一个问题,@Autowired注解是否是通过setter方法注入的?

@Autowired基本用法

首先,@Autowired基本用法如下:

  1. 注解在类成员属性上
  2. 注解在setter方法上
  3. 注解在类构造器上

我这里为了验证问题,仅使用字段的方式看看

基于字段的方式

请看下面的例子:

@RestController
@Api(tags = "用户前端控制器")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping(value="/testUserService")
    @ApiOperation(value="测试userService的注入")
    public String testUserService(){
        return String.valueOf(userService==null);
    }

}

上面的例子执行后:
在这里插入图片描述
这里可以看到,userService即使没有setter方法,还是能够注入成功的,说明了@Autowired的注入并不是依靠setter方法注入的。

究竟@Autowired是怎么样注入的?

第一点,首先我想看看是不是有UserController自动产生了setter方法。
通过jclasslib分析字节码,结果如下图,只看到两个方法,所以@Autowired没有自动产生setter方法。
在这里插入图片描述
那么,既然不是通过setter方法,也不是通过构造器注入的话,在我印象中还可以通过反射手段进行赋值。

AutowiredAnnotationBeanPostProcessor
该类是@Autowired的具体实现类,先预览一下类方法,IDEA快捷键Ctrl+F12
在这里插入图片描述
有机会介入到Bean的创建过程,只有后置处理的那几个方法,postProcessXXX,而且有一个方法是已过时的。现在看看它们做了什么。

postProcessMergedBeanDefinition
这个方法是实现MergedBeanDefinitionPostProcessor接口的方法,看起来像是收集元信息然后封装为InjectionMetadata

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		// 1. 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

postProcessProperties:注入过程
这个方法是实现InstantiationAwareBeanPostProcessor接口的方法

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 1. 寻找通过@Autowired注解的属性或者方法
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
		 	// 2. 注入
			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;
	}

回顾一下Bean实例创建的流程,路径是AbstractApplicationContext.refresh()->finishBeanFactoryInitialization()->getBean()方法。
getBean方法的流程大致可以分为创建实例,填充实例,初始化实例三步。
在这里插入图片描述
我经过debug验证的结论:
在实例化阶段,会调用MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition的方法,AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition方法,作用是将有@Autowired注解的成员扫描出来,封装为InjectionMetadata,在实例化上面的UserController的时候,刚好就是size = 1;

调用上面说到的postProcessMergedBeanDefinition方法
在这里插入图片描述
检测出@Autowried注解的成员
在这里插入图片描述

在填充阶段,AutowiredAnnotationBeanPostProcessorpostProcessorProperties方法会被调用,作用是解析InjectionMetadata,并使用反射,从容器中获取实例设置到成员变量中。

		/**
		 * 这个方法是在AutowiredAnnotationBeanPostProcessor 中
		 */
		@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			//获取Field对象
			Field field = (Field) this.member;
			//value赋值
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			//...
			value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			//...	
			//调用Field.set方法设置赋值
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

结论

@Autowired可以不需要setter方法,因为在AutowiredAnnotationBeanPostProcessor 中的inject方法显示,是通过反射手段填充的。

参考

【https://blog.csdn.net/qq_19782019/article/details/85038081】
【https://mp.weixin.qq.com/s/_OL0jR1eJoD9oM4Og9ZzjA】

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值