首页 - 信息 - 【第88期】面试官问:你能告诉我Spring中接口bean是如何注入的吗?

【第88期】面试官问:你能告诉我Spring中接口bean是如何注入的吗?

2023-10-04 06:11
2022年5月17日下午3:48 • 面试问题 • 阅读 4 点击上方“Java面试题精选”,关注公众号 面试时画图,查漏补缺 >>额外号:以前的面试题,10道为单位,放在这个公众号菜单栏->面试题。如果您需要它们,欢迎您阅读。 问: 这个问题困扰了我很长时间。我一直想知道这个接口的bean是怎么注入的?因为我只看到使用@Service注入的实现类serviceImpl,那么使用时如何获取接口,并且还可以调用实现类的方法呢?这个接口是什么时候自动注入并与实现类关联的? ? 界面 公共接口测试服务{ 公共字符串测试();} 实现类实现 @Service公共类TestServiceImpl实现TestService{ @Override public String test() { return "TestServiceImpl"; } }} 控制器调用: @RestController公共类TestCtl { @Autowired私有TestService testService; @RequestMapping("/test") public String test() { return testService.test(); } }} 请求结果: 回答: 后来了解到,接口中没有注入任何bean,只注入了实现serviceImpl类的bean,并且接口仅用于接收。这里讲一下@Autowired/@Resource的注入原理:@Autowired是spring的一个注解。默认情况下,Autowired 首先按 byType。如果找到多个 bean,则它们根据 byName 进行比较。如果多了,则报异常; @Resource是JDK1.6支持的注解。它默认是按名称(Byname)组装的。如果不指定name属性,则在字段上写入注解时,默认取字段名,按名称进行搜索。如果注解写在setter方法上,则默认使用属性名进行装配。仅当未找到与名称匹配的 bean 时才按类型连线。但需要注意的是,如果指定了name属性,则只会根据name进行组装。 下面讲一下Controller获取实例的过程:使用@Autowired,程序在spring容器中寻找TestService类型的bean。恰好发现该类型的bean只有一个,即testServiceImpl,于是testServiceImpl就自动组装到了控制器实例testService中。 ,testService实际上是TestServiceImpl实现类; 如果使用@Resource,首先会在容器中查找名为testService的bean,但是没有找到,因为容器中的bean名称为TestServiceImpl(如果@Service没有指定bean的value属性,则为testServiceImpl的名称)注入的bean为类名(如果指定则为指定的名称),然后按类型查找TestService类型的bean,找到唯一的TestService类型的bean(即TestServiceImpl),这样实例的自动组装就成功了。更多面试题欢迎关注公众号java面试题精选 笔记: byName是通过参数名称自动组装的。如果一个bean的名称与另一个bean的属性相同,则会自动组装。 byType 通过参数的数据类型自动组装。如果一个bean的数据类型与另一个bean的property属性的数据类型兼容,则会自动组装。从效率上来说,@Autowired/@Resource类似,但是建议使用@Resource,因为当接口有多个实现时,@Resource可以通过name属性直接指定实现类,而@Autowired必须在与@Qualifier注释一起使用。而@Resource是jdk的一个注解,可以和Spring解耦。 问: 如果一个接口有多个实现类,通过注解获取实例时如何知道应该获取哪个实现类serviceImpl呢? 添加了另一个实现类TestServiceImpl2 @Service公共类TestServiceImpl2实现TestService{ @Override public String test() { return "TestServiceImpl2"; } }} 回答: 如果有多个实现类,可以通过以下两种方式指定使用哪个实现: 1. 通过指定bean的名称来指定要实例化的类。 @Autowired需要和@Qualifier配合使用,如下: @Autowired @Qualifier("testServiceImpl") 私有 TestService testService; @Resource可以直接指定name属性的值,但也可以使用@Qualifier(有点多余……) @Resource(name = "testServiceImpl") 私有 TestService testService; 如果@Resource没有明确指定name值,它会自动使用实例变量的名称作为name的值,所以你也可以直接这样写:    @Resource private TestService testServiceImpl; 2.通过在实现类上添加@Primary注解来指定默认加载类 @Service@Primary公共类TestServiceImpl2实现TestService{@Override public String test() { return "TestServiceImpl2"; } }} 这样,如果使用@Autowired/@Resource获取实例时不指定bean名称,则默认获取TestServiceImpl2的bean。如果指定了bean名称,则以指定的bean名称为准。 问: 为什么我们要调用多余的接口,而不是直接调用实现serviceImpl类的bean,这样简单明了? 回答: 1、也可以直接获取实现serviceImpl类的bean; 2、至于增加一层接口的原因:一是AOP程序设置的思想指导,是别人调用的接口。调用者只想知道方法和功能,而不关心这个方法的内部逻辑是如何实现的;其次,可以减少各个模块之间的关联,实现松耦合、程序分层、高扩展性,使程序更加灵活。除了它对规范的杰出贡献之外,最重要的是它对多态性的运用;继承只能以单一方式继承。接口可以通过多种方式实现 3、当业务逻辑简单,改动较少,且项目是自用时,省略接口,直接使用实现类更简单、清晰;否则,建议使用该接口; 来源:www.gsm-guard.net/aland-1415/p/11991170.html 最后五期 【第82期】面试时被问到SQL优化的时候,这篇文章就该读! 【第83期】面试时被问到Redis和MongoDB有什么区别?看看这里 【第84期】面试中关于设计模式你能问什么?例如我们来说三种单例模式的实现 【第85期】浅谈Java面向对象设计六大原则,中高级面试常见问题! 【第86期】五个棘手的String面试问题及答案 而不是在网上搜索问题?还不赶快关注我们吧~ 版权声明:本文内容由网友自愿贡献,本文所表达的观点仅代表作者自己的观点。本网站仅提供信息存储空间服务,不拥有任何所有权,也不承担相关法律责任。如果您发现本站有任何涉嫌侵权/非法内容,请发送邮件举报。一经核实,该网站将立即删除。 本文由斑马博客整理。本文链接为:https://www.gsm-guard.net/index.php/post/6852.html