如何做网络投票网站,深圳市在建项目,温岭网站建设公司,濮阳网格化app一、 前言
平常我们在使用spring框架开发项目过程中#xff0c;会使用Autowired注解进行属性依赖注入#xff0c;一般我们都是声明接口类型来接收接口实现变量#xff0c;那么使用父类类型接收子类变量#xff0c;可以注入成功吗#xff1f;答案是肯定可以的#xff01;…一、 前言
平常我们在使用spring框架开发项目过程中会使用Autowired注解进行属性依赖注入一般我们都是声明接口类型来接收接口实现变量那么使用父类类型接收子类变量可以注入成功吗答案是肯定可以的
二、结果验证
我们在项目中声明如下三个类
1. 测试代码
TestParent
public class TestParent {protected void test() {System.out.println(I am TestParent...);}
}TestSon
importorg.springframework.stereotype.Component;Component
public class TestSon extends TestParent {publicvoidtest() {System.out.println(I am TestSon...);}
}TestType
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importjavax.annotation.PostConstruct;Component
public class TestType {Autowiredprivate TestParent testParent;PostConstructpublicvoidinit() {System.out.println();testParent.test();System.out.println();}
}2. 验证测试
启动项目 可以看到注入成功了说明依赖注入使用父类类型接收子类变量是没有问题的。
3. Autowired注解使用细节
还是上面的案例我们修改一下TestParent类的代码把TestParent也交由Spring容器管理
importorg.springframework.stereotype.Component;Component
public class TestParent {protected void test() {System.out.println(I am TestParent...);}
}运行测试 可以发现此时也可以注入成功但是执行对象变成了父类有经验的大佬已经猜到是什么情况了没猜到的也没有关系我们再修改一下TestType类的代码
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importjavax.annotation.PostConstruct;Component
public class TestType {Autowiredprivate TestParent test;PostConstructpublic void init() {System.out.println();test.test();System.out.println();}
运行结果 此时居然注入报错了提示我们有两个bean冲突了不能进行依赖注入
三、原理分析
为什么会出现上面的现象呢是由于Autowired注入时是先按照类型找到bean实例名称再按照beanName去获取真正需要注入的bean如果有多个实例时会尝试通过需要注入的字段名称与按照类型筛选出来的beanName对比如果能够对比出唯一beanName也会按照此beanName去获取bean实例注入如果不能够确定唯一bean实例就会抛出异常了。
下面我们进行源码跟踪
Autowired注解解析的核心逻辑入口在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor后置处理器中我们进入该类中进行断点调试。
通过阅读源码我们可以发现依赖注入入口方法是postProcessProperties()方法 进入org.springframework.beans.factory.annotation.InjectionMetadata#inject方法 继续调试由于我们目前是字段方式注入所以选择org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement类 查看方法细节 我们继续跟踪org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue方法 进入org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency方法 继续进入org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency方法 继续进入org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates方法 进入org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class, boolean, boolean)看一下bean的筛选逻辑 跟踪进入org.springframework.beans.factory.support.DefaultListableBeanFactory#doGetBeanNamesForType方法 查看类型匹配判断方法org.springframework.beans.factory.support.AbstractBeanFactory#isTypeMatch(java.lang.String, org.springframework.core.ResolvableType, boolean) 判断核心方法org.springframework.core.ResolvableType#isInstance 看到isAssignableFrom方法就知道为什么子类变量也可以成功注入父类类型了此时子类变量也是可以成功匹配上的。
筛选出所有类型匹配的beanName以后回到org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates做一下是否可以进行依赖注入的判断返回beanName信息 然后回到org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency方法中如果有多个类型会按照字段名称和beanName匹配再筛选 最终确定获取到可以注入的bean实例。
四、写在最后
以上流程还是比较清晰的分析过程中有一些分支流程没有过度关注有兴趣的小伙伴也可以参考流程自己进行debug调试分析。