static不进行注入
如图所示, 需要注意的是, 如果当前的属性是 static的, 那么直接return掉, 不进行属性的注入
为什么一个字段是static的, 不将其当做注入点
如果我们的 Bean对象不是单例的, 而是多例或者其他类型的, 那么获取一次Bean都会将其重新创建一遍, 这不符合我们对 static静态资源的预期
如果获取到相关的注解
如果获取到相关的注解了, 那么继续往下走,会先执行一个方法, 然后把当前这个字段设置为一个注入点
在我们的 @Autowired注解中, 可以进行配置 required, 这个值默认是true的, 他的含义是: 如果在依赖注入的时候, 没有找到这个 Bean是会报错的, 如果设置为 false之后, 在依赖注入期间没有找到这个 Bean就不会报错了
下面的代码, 就是对 @Autowired注解属性配置的单独处理
boolean required = determineRequiredStatus(ann); 复制代码
遍历当前 Bean所有的方法
接着往下走, 就是遍历当前 Bean所有的方法了
还是一样的, 简单流程如下:
- 过滤掉桥接方法
- 去找方法上面有没有加注解
- 是不是静态方法
- 某个方法的参数等于0, 则打印日志
- 解析 required值
- 封装成AutowiredMethodElement类
- 当成注入点加入 currElements集合中
桥接方法, 是专门用来处理一些特殊的情况的
如下图所示, 如果是用以下这种方式编写代码, 那么在字节码文件中就会发现两个 setOrderService方法, 这个时候就需要桥接方法帮助我们找到原方法
网络异常,图片无法展示|
遍历父类, 去循环上面的操作
注意, 我们这个方法是一个 do while循环, 先执行当前 Bean再去遍历 父Bean
return
将当前类和父类的注入点都找出来, 封装成一个对象, 把这个对象返回并且缓存, 存到外面的方法
注入点进行注入
根据我们之前进行 Bean生命周期的分析, 接下来会执行 postProcessProperties方法
取出注入点
在这个方法的第一行代码, 就是取出注入点, 具体代码如下所示, 之前已经全部注入完了, 这里就不详细讲了
给注入点进行注入
如下图所示, 接下来获取到所有的注入点, 然后对其进行遍历
注意, 这里查看具体处理方法的时候, 不要直接点进 element.inject(target, beanName, pvs);方法, 因为我们是子类继承父类去实现的, 所以要去找子类的实现方法
网络异常,图片无法展示|
字段的注入实现
流程简单说明:
- 找出注入点封装的字段
- 获取字段的对象
- 获取缓存, 我们没有, 直接进入else
- 调用方法 resolveFieldValue
- 根据字段的类型, 名字去找具体的值(下一篇文章详细讲解)
- 找到之后通过反射为字段复制
字段的注入实现代码如下图所示:
方法的注入实现
流程简单说明:
- 如果pvs中已经有当前注入点的值了,则跳过注入
- 找出方法对象
- 获取缓存, 我们没有, 直接进入else
- 根据 @Autowired注解的参数返回对象数组
- 执行 method.invoke(bean, arguments);
方法的注入实现代码如下图所示:
五、属性注入方法的执行
回到我们本标题的最开始, 看这个for遍历, 如下图所示
六、属性赋值
可以看到, 在上面的代码分析过程中, 并没有实际的做属性赋值操作, 那么具体的属性赋值实际上是在该方法的最后一行
这个方法实际上就是将 BeanDefinition中的属性和值设置到 Bean对象中, 感兴趣的可以去看一下