大家都知道@Service注入的是實現類serviceImpl,那使用時怎么能獲取到接口,而且還能調用到實現類的方法。
接口:
public interface TestService{ public String test(); }
實現類:
@Service public class TestServiceImpl implements TestService{ @Override public String test(){ return "TestServiceImpl "; } }
Controller類:
@RestController public class TestController{ @Autowired private TestService testService; @RequestMapping("/test") public String test(){ return testService.test(); } }
請求結果:

其中只注入了實現類serviceImpl的bean,接口只是用來接收的。這里就要說到@Autowired/@Resource的注入原理:@Autowired是Spring的注解,Autowired默認先按byType,如果發現找到多個bean,則再按照byName方式比對,如果還有多個bean,則報錯Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException;@Resource是JDK1.6支持的注解,默認按照byName進行裝配。如果沒有指定name屬性,當注解寫在字段上時,默認取字段名按名稱查找,當注解寫在setter方法上默認取屬性名,當找不到與名稱匹配的bean時才按照類型匹配。
再來說Controller獲取實例的過程:使用@Autowired,程序在spring的容器中查找類型時TestService的bean,剛好找到有且只有一個此類型的bean,即TestServiceImpl,所以就把testServiceImpl自動裝配到了Controller的實例TestService中。
問:如果一個接口有多個實現類時,通過注解獲取實例時怎么知道應該獲取的是哪一個實現類serviceImpl呢?
增加一個新的實現類:
@Service public class TestServiceImpl2 implements TestService{ @Override public String test() { return "TestServiceImpl2"; } }
1.通過指定bean的名稱來明確到底要實例哪一個類
@Autowired需要結合@Qualifier,注:實現類的開頭小寫類名TestServiceImpl2->testServiceImpl2
@Autowired @Qualifier("testServiceImpl2") private TestService testService;
@Resource也可以使用(name="testServiceImpl2"),如果不顯示的指定name值,就會自動把實例變量的名稱作為name的值
@Resource private TestService testServiceImpl2;
2.通過在實現類上添加@Primary注解來指定默認加載類,如果任然指定了bean的名字則以指定的為准
@Service @Primary public class TestServiceImpl2 implements TestService{ @Override public String test() { return "TestServiceImpl2"; } }
問:為什么非要調用接口來多此一舉,而不直接調用實現類serviceImpl的bean來得簡單明了呢?
直接使用serviceImpl的bean是可以的,這樣加一層接口的原因:1.AOP程序的思想,給別人調用的接口,調用這只想知道方法和功能,而對於這個方法內部邏輯實現並不關心。2.降低各個模塊間的關聯,實現松耦合、程序分成、最主要的體現了繼承只能單繼承,接口卻可以多實現
