详解Spring中接⼝的bean是如何注⼊的
Question:
这个问题困扰了我好久,⼀直疑问这个接⼝的bean是怎么注⼊进去的?因为只看到使⽤@Service注⼊了实现类serviceImpl,使⽤时怎么能获取的接⼝,⽽且还能调⽤到实现类的⽅法,难道这个接⼝是在什么时候⾃动注⼊了进去,且和实现类关联上了?
接⼝
public interface TestService {
public String test();
}
实现类impl
@Service
public class TestServiceImpl implements TestService {
@Override
public String test() {
return "TestServiceImpl";
}
}
Controller的调⽤:
@RestController
public class TestCtl {
@Autowired
private TestService testService;
@RequestMapping("/test")
public String test() {
st();
}
}
请求结果:
Answwer:
后来才知道,并没有注⼊接⼝的bean,只注⼊了实现类serviceImpl的bean,接⼝只是⽤来接收的。
resource和autowired注解的区别这⾥就要说到@Autowired/@Resource的注⼊原理了:@Autowired是Spring的注解,Autowired默认先按byType,如果发现到多个bean,则,⼜按照byName⽅式⽐对,如果还有多个,则报出异常;@Resource 是JDK1.6⽀持的注解,默认按照名称(Byname)进⾏装配, 如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查,如果注解写在setter⽅法上默认取属性名进⾏装配。当不到与名称匹配的bean时才按照类型进⾏装配。但是需要注意的是,如果name属性⼀旦指定,就只会按照名称进⾏装配。
再来说Controller获取实例的过程:使⽤@Autowired,程序在spring的容器中查类型是TestService的bean,刚好到有且只有⼀个此类型的bean,即testServiceImpl,所以就把testServiceImpl⾃动装配到了controller的实例testService
中,testService其实就是TestServiceImpl实现类;
如果使⽤的是@Resource,则是先在容器中查名字为testService的bean,但并没有到,因为容器中的bean名字是TestServiceImpl(如果@Service没指定bean的value属性,则注⼊bean的名字就是类名,如果指定了则是指定的名字),然后再通过类型查TestService类型的bean,到唯⼀的了个TestService类型bean(即TestServiceImpl),所以就⾃动装配实例成功了。更多⾯试题,欢迎关注Java⾯试题精选
Note:
byName 通过参数名⾃动装配,如果⼀个bean的name 和另外⼀个bean的 property 相同,就⾃动装配。
byType 通过参数的数据类型⾃动⾃动装配,如果⼀个bean的数据类型和另外⼀个bean的property属性的数据类型兼容,就⾃动装配
效率上来说@Autowired/@Resource差不多,不过推荐使⽤@Resource⼀点,因为当接⼝有多个实现时@Resource直接就能通过name属性来指定实现类,⽽@Autowired还要结合@Qualifier注解来使⽤,且@Resource是jdk的注释,可与Spring解耦。
Question:
如果⼀个接⼝有多个实现类时,通过注解获取实例时怎么知道应该获取的是哪⼀个实现类serviceImpl呢?
再增加了⼀个实现类TestServiceImpl2
@Service
public class TestServiceImpl2 implements TestService {
@Override
public String test() {
return "TestServiceImpl2";
}
}
Answer:
多个实现类的话可通过以下2种⽅式来指定具体要使⽤哪⼀个实现:
1、通过指定bean的名字来明确到底要实例哪⼀个类
@Autowired 需要结合@Qualifier来使⽤,如下:
@Autowired
@Qualifier("testServiceImpl")
private TestService testService;
@Resource可直接通过指定name属性的值即可,不过也可以使⽤@Qualifier(有点多此⼀举了…)
@Resource(name = "testServiceImpl")
private TestService testService;
@Resource如果不显⽰的指定name值,就会⾃动把实例变量的名称作为name的值的,所以也可以直接这样写:
@Resource
private TestService testServiceImpl;
2、通过在实现类上添加@Primary注解来指定默认加载类
@Service
@Primary
public class TestServiceImpl2 implements TestService {
@Override
public String test() {
return "TestServiceImpl2";
}
}
这样如果在使⽤@Autowired/@Resource获取实例时如果不指定bean的名字,就会默认获取TestServiceImpl2的bean,如果指定了bean的名字则以指定的为准。
Question:
为什么⾮要调⽤接⼝来多此⼀举,⽽不直接调⽤实现类serviceImpl的bean来得简单明了呢?
Answer:
1、直接获取实现类serviceImpl的bean也是可以的;
2、⾄于加⼀层接⼝的原因:⼀是AOP程序设置思想指导,给别⼈调⽤的接⼝,调⽤者只想知道⽅法和功能,⽽对于这个⽅法内部逻辑怎么实现的并不关⼼;⼆是可以降低各个模块间的关联,实现松耦合、程序分层、⾼扩展性,使程序更加灵活,他除了在规范上有卓越贡献外,最精髓的是在多态上的运⽤;继承只能单⼀继承,接⼝却可以多实现
3、当业务逻辑简单,变更较少,项⽬⾃⽤时,省略掉接⼝直接使⽤实现类更简单明了;反之则推荐使⽤接⼝;
总结
到此这篇关于详解Spring中接⼝的bean是如何注⼊的⽂章就介绍到这了,更多相关Spring接⼝的bean注⼊内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。