spring bean依赖注入
1.依赖注入的步骤
结合调用方法,从大到小讲述中间涉及到代码以及bean创建过程中的注入点。
这里涉及的逻辑是在AbstractAutowireCapableBeanFactory的doCreateBean方法中实现的,是bean创建生命周期中的重要的一环。
-
实例化bean对象之后,即在applyMergedBeanDefinitionPostProcessors方法中调用MergedBeanDefinitionPostProcessor实现类中的postProcessMergedBeanDefinition方法:
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}这个注入点对spring合并好的beandefinition做一些定制化的处理,其中就包括寻找bean中的注入点,resource、value、autowired这些注解的预处理都是在这个注入点实现的。
具体的实现类包括CommonAnnotationBeanPostProcessor(处理resource注解)和AutowiredAnnotationBeanPostProcessor(处理autowired、value注解)。
具体寻找注入点的过程即通过反射遍历bean的field和method,检查是否有目标注解,扫描的结果放到cache中,供之后做注入,其中对字段的过滤中,不会记录静态字段,因为对于原型bean,如果静态字段也可以做注入,就会出现不合理的结果,对方法的过滤中,有涉及桥接方法的处理,对于实现的接口中的方法,编译的字节码中会出现两个同名方法,其中一个会被标记为桥接方法,spring不会扫描这些方法上的注解,同时spring同样不会关心静态方法上的注解。
-
标记完注入点之后,要做的就是基于注解找到要注入的内容了
这是在populateBean(beanName, mbd, instanceWrapper)方法中实现的,这个方法中做的就是各种依赖注入,包括前面讲的在bean注解或者xml标签中标记的autowired属性这种废弃的方式,以及基于注解的更灵活的方式。注入点是InstantiationAwareBeanPostProcessor中的postProcessProperties方法,上一步中讲的两个BeanPostProcessor类均实现了这个接口,所以前后两个注入点是在同一个bean中做的。
对于autowired以及value注解的处理中,开始同样是调用在上一步中调用过的findResourceMetadata方法,不同的是,这一步直接使用上一步缓存好的值,取到值之后,即调用InjectionMetadata的inject方法,做真正的注入,这里AutowiredAnnotationBeanPostProcessor针对field和method两种情况分别实现了注入点内部类AutowiredFieldElement以及AutowiredMethodElement,它们都继承了InjectionMetadata.InjectedElement。
下面是找注入值的大体步骤
-
基于type找到所有的候选bean,之后对每个候选bean做2 3 4的过滤
-
检查是否autowireCandidate的属性为false,如果是的话,丢弃之
-
基于范型做匹配
-
基于Qualifier注解做匹配
-
如果没有候选bean,如果required为true即报错;如果只有一个了,直接返回;如果有多个就按照6 7 8做过滤
-
如果有候选bean使用Primary注解修饰,直接返回
-
基于Priority注解排序
-
到这一步,如果找到的依旧是多个候选bean,直接报错,如果没有候选bean,看下注入点的require参数,如果不是false,同样报错。
-
2.中间用到的设计模式
在过滤候选bean的时候使用到了AutowireCandidateResolver接口的isAutowireCandidate方法,这个方法一共有三种实现,对于每个子类的实现方法中,都会有如下代码:
if (!super.isAutowireCandidate(bdHolder, descriptor)) {
// If explicitly false, do not proceed with any other checks...
return false;
}
即,首先调用父类的判断逻辑,如果父类通过,再调用自己的判断逻辑。
这里是责任链模式
相关文章
- javaEE是什么
- java关键字是什么
- java编译命令是什么
- java 自定义表单 挂靠流程 模块设计方案
- linux配置java环境变量
- java怎么从键盘输入一个数
- 初学Tips - 为啥Flink的Java模块需要Scala的版本后缀
- T资讯 | 一亿多条仇恨言论喂养出有史以来最邪恶的AI、360企业安全云或将上线“一键强制下班”功能、C++即将超越Java
- 三种方法+三种选型,用分布式锁还怕啥并发问题呀?
- Java 技术篇 - java同时连接多种数据库执行sql语句的兼容性验证,数据库类型包括:oracle、sqlserver、DB2、人大金仓、达梦、PG、瀚高、polardb
- Java 技术篇 - 前端浏览器发送一次url请求后端ServerSocket接收到两次请求原因及解决方法,GET /favicon.ico HTTP/1.1问题处理
- Java 技术篇 - ServerSocket接收http的url请求中包含中文的处理方法,URLDecode与URLEncode,url解码与编码
- Java 技术篇 - 通过exe4j打包后的程序运行过程中出现中文乱码问题解决
- Java 技术篇 - 从指定的web网页页面中读取html内容实例演示,从http协议下的url地址中读取web页面内容方法
- Java 技术篇 - 启动web服务接收浏览器请求并响应实例演示,解决socket响应浏览器显示中文乱码问题,web服务response响应设置浏览器显示字体方法
- Java 技术篇 - 连接oracle数据库执行sql使用close()关闭createStatement()无效无法清除游标缓存问题解决,报“ORA-01000: 超出打开游标的最大数“错误解决方法
- Java 技术篇-使用poi开源jar包实现读取excel实例演示,poi-3.17.jar获取
- Java 技术篇-linux系统下安装jdk、设置java环境变量实例演示
- Java 技术篇-利用ClipboardOwner实现实时监听剪切板功能实例演示
- Java 技术篇-借助自定义对象实现函数返回多个不同类型的值实例演示