@Autowired的原理简识
一、@Autowired是什么
(1)存在范围
@Autowired注解是属于spring的容器配置的一个注解,因此@Autowired注解是一个用于Spring容器配置的注解。与它同属容器配置的注解还有:
@Primary(含义:首选项,当类型冲突情况下,此注解修饰类作为首选注入
位置:修饰类
注意:不能单独使用),
@Qualifier(value="注入的id")
含义:按照名称装配
位置:修饰成员变量
注意:不能单独使用
@Resource(name="注入的id")
含义:按照名称装配
位置:修饰成员变量
注意:单独使用......等等。
(2)定义解释
@Autowired注解又称:自动装配。在Spring中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起。
二、什么情况下使用到@Autowired
前情回顾:使用spring开发时,进行配置Spring bean元数据主要有三种方式。
一:基于 XML 配置
二:基于 注解 配置:Spring2.5以上版本支持
三:基于Java 配置:Spring3.0以上版本支持
基于注解配置时,完成自动化装配Bean的情况下,@Autowired的使用便会使Spring自动满足bean之间的依赖注入。
三、如何使用@Autowired
(1)使用位置:修饰成员变量
@Controller
public class StudentControllerImp implements IStudentController {@Autowiredprivate IStudentService service;@Overridepublic void save() {System.out.println("======controler的新增方法=======");service.save();}
}
(2)在xml文件中完成组件扫描设置
<!--扫描包--><context:component-scan base-package="com.apesource"></context:component-scan>
com.apesource---包名;启用组件扫描,默认当前配置类所在包为基础包
四、@Autowired注解是如何实现的
--------------------------------以下部分内容参考于相关公众号文章-----------------------------------------------
(1)打开@Autowired源码
package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {boolean required() default true;
}
我们知道: 在java中注解实现的核心技术是反射
(2)我们让看一下源代码中的元注解(也就是上面提到的注解的注解),总共有4个如下:
@Target,说明的是Annotation所修饰的对象范围
@Retention,定义了该Annotation被保留的时间长短:使用这个元注解可以对 Annotation的“生命周期”限制
@Documented,用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员
@Inherited;元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。
(3)在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation
之中,该包的内容如下:
Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor
之中,红色箭头所指的类。其中的核心处理代码如下:
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz; //需要处理的目标类do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();//通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性ReflectionUtils.doWithLocalFields(targetClass, field -> {MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {校验autowired注解是否用在了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);currElements.add(new AutowiredFieldElement(field, required));}});//和上面一样的逻辑,但是是通过反射处理类的methodReflectionUtils.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));}});//用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理 elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}
最后这个方法返回的是一个InjectionMetadata集合。由两部分组成:
一是我们处理的目标类,二就是上述方法获取到的所以elements集合。
源代码:
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;
有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:
源代码:
@Deprecated@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {return postProcessProperties(pvs, bean, beanName);}
它调用的方法是InjectionMetadata中定义的inject方法,如下
源代码
@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {value = resolveFieldValue(field, bean, beanName);}if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}
然后调用inject方法;
源代码
@Overrideprotected 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) {try {arguments = resolveCachedArguments(beanName);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvearguments = resolveMethodArguments(method, bean, beanName);}}else {arguments = resolveMethodArguments(method, bean, beanName);}if (arguments != null) {try {ReflectionUtils.makeAccessible(method);method.invoke(bean, arguments);}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}
在这里的代码当中我们也可以看到,是inject也使用了反射技术并且依然是分成字段和方法去处理的。在代码里面也调用了makeAccessible这样的可以称之为暴力破解的方法,但是反射技术本就是为框架等用途设计的。
对于方法的话,本质就是去调用这个方法,因此这里调用的是method.invoke.
getResourceToInject方法的参数就是要注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它。
总结:
使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,将其变为实例对象。
@Autowired的原理简识相关推荐
- Webpack模块化原理简析
webpack模块化原理简析 1.webpack的核心原理 一切皆模块:在webpack中,css,html.js,静态资源文件等都可以视作模块:便于管理,利于重复利用: 按需加载:进行代码分割,实现 ...
- Android Handler与Looper原理简析
一直感觉自己简直就是一个弱智,最近越来越感觉是这样了,真的希望自己有一天能够认同自己,认同自己. 本文转载于:https://juejin.im/post/59083d7fda2f60005d14ef ...
- grpc通信原理_gRPC原理简析
gRPC原理简析 gRPC是由谷歌提出并开发的RPC协议,gRPC提供了一套机制,使得应用程序之间可以进行通信. 降级开发者的使用门槛,屏蔽网络协议,调用对端的接口就像是调用本地的函数一样.而gRPC ...
- Android V1及V2签名原理简析
Android为了保证系统及应用的安全性,在安装APK的时候需要校验包的完整性,同时,对于覆盖安装的场景还要校验新旧是否匹配,这两者都是通过Android签名机制来进行保证的,本文就简单看下Andro ...
- CRC原理简析——史上最清新脱俗简单易懂的CRC解析
CRC原理简析 1. CRC校验原理 CRC校验原理根本思想就是先在要发送的帧后面附加一个数(这个就是用来校验的校验码,但要注意,这里的数也是二进制序列的,下同),生成一个新帧发送给接收端.当然,这个 ...
- Java的定时器Timer和定时任务TimerTask应用以及原理简析
记录:272 场景:Java JDK自带的定时器Timer和定时任务TimerTask应用以及原理简析.在JDK工具包:java.util中可以找到源码,即java.util.Timer和java.u ...
- 自考计算机网络原理简答题,自考计算机网络原理简答题汇总.doc
自考计算机网络原理简答题汇总 2013-440.TCP可用的端口号有65536个,请说明这些端口号的使用规定. P139第六章 (1)端口号小于256的定义为常用端口,服务器一般都是通过常用端口来识别 ...
- 转子接地保护原理_发变组转子接地保护原理简析
发变组转子接地保护原理简析 发电机转子接地故障是常见的故障之一, 发生一点接地, 对发电机本身并不直接构成危 害,此时可通过转移负荷,平稳停机后,再查故障点:若在此基础上又发生另外一点接地, 将会严重 ...
- 深入浅出kafka原理-1-初识只作乍见之欢
目录 前言: 1.由来 2.特点 3.使用场景 4.两种模式 1.Kafka名词解释 2.Kafka历史由来 版本号 3.Kafka术语 前言: 1.由来 为什么使用消息队列? 从系统之间有通信需求开 ...
最新文章
- vc mysql控件_VC++使用ActiveX控件连接和操作数据库
- 很好的linux启动说明( bootsect.S、setup.S、head.S)
- awgn信道中的噪声功率谱密度_从OFC2020看高级算法在光通信中的应用
- POJ 3648 Wedding
- python布尔类型运算_9.python的布尔类型与流程控制
- 地表上最强编程语言——C语言
- 解决从github上下载代码仓库慢的问题
- vmware tools 的安装(Read-only file system 的解决)
- 芒果云 在线代码编辑器
- The essense of the software atchitecture
- 奇妙的裴波那契数列和黄金分割
- 原生JavaScript实现entries和fromEntries
- 跟领导汇报工作时,这句话建议你不要说
- 基于unity自己写光追。
- maya计算机内存不足请保存,Word突然出现无法保存内存不足怎么办
- 2022暑期项目实训(二)
- 实现系统滚动条换肤功能
- raspberry pi_我如何从Mac Mini迁移到Raspberry Pi
- 关于秘密共享方案的实例(shamir)
- 【项目管理】采购、外包、合同
热门文章
- [安全] AD域解释 , 域和组的区别?
- 攻防世界we区newer题目
- 2019计算机小高考成绩,小高考没过怎么办 2021小高考难度如何
- 前端项目微金所1 - bootstrap模板,Compatible(兼容),Viewport(视口),条件注释,第三方依赖,MediaQuery媒体查询...
- Mysql主从同步报错解决:Error executing row event: Table zabbix.history-uint doesnt exist
- 2008年度回顾:决胜路由应用时代
- Android Studio常用快捷键
- matlab 点云根据法向量投影到六个平面
- android单元测试教程,Android单元测试-Junit
- 低版本android无法连接iPhone手机个人热点问题