把DAO實現類注入到service實現類中,把service的接口(注意不要是service的實現類)注入到action中,注
入時不要new 這個注入的類,因為spring會自動注入,如果手動再new的話會出現錯誤,然后屬性加上
@Autowired后不需要getter()和setter()方法,Spring也會自動注入。至於更具體的內容,等對注入的方式更
加熟練后會做個完整的例子上來。
首先說@Service、@Repository注解的作用吧,也就是IOC的思想,IOC中文就是控制反轉,但這個晦澀難懂,所以有個新詞代替這個詞就是依賴注入,就是,調用類對某個接口實現類的依賴調用由第三方(Spring的容器)來實現,以移除調用類對某一接口實現類的依賴,從而減少代碼的耦合度。
那么通過控制反轉(IOC)是怎么實現減少耦合的呢?總結網上的說法,從兩個角度出發
1、控制反轉① 軟件系統在沒有引入IoC容器之前,對象A依賴對象B,那么A對象在實例化或者運行到某一點的時候,自己必須主動創建對象B或者使用已經創建好的對象B,其中不管是創建還是使用已創建的對象B,控制權都在我們自己手上。
②如果軟件系統引入了Ioc容器之后,對象A和對象B之間失去了直接聯系,所以,當對象A實例化和運行時,如果需要對象B的話,IoC容器會主動創建一個對象B注入到對象A所需要的地方,。
③ 通過前面①②的對比,可以看到對象A獲得依賴對象B的過程,由主動行為變成了被動行為,即把創建對象交給了IoC容器處理,控制權顛倒過來了,這就是控制反轉的由來!
工廠模式
工廠模式是指當應用程序中甲組件需要乙組件協助時,並不是在甲組件中直接實例化乙組件對象,而是通過乙組件的工廠獲取,即該工廠可以生成某一類型組件的實例對象。在這種模式下,甲組件無需與乙組件以硬編碼的方式耦合在一起,而只需與乙組件的工廠耦合
那么這樣的話,通過依賴注入就可以完全不用關心對象的生命周期,什么時候被創建,什么時候銷毀,只需直接使用即可,對象的生命周期由提供依賴注入的框架來管理,從而,讓使用框架者,可以將重心完全放到業務邏輯處理的開發上。
2、spring之aop
1) 在業務系統里除了要實現業務功能之外,還要實現如權限攔截、性能監控、事務管理等非業務功能。
通常的作法是非業務的代碼穿插在業務代碼中,從而導致了業務組件與非業務組件的耦合。
2) aop面向切面編程,就是將這些分散在各個業務邏輯代碼中的非業務代碼,通過橫向切割的方式抽取到一個獨立的模塊中,從而實現業務組件與非業務組件的解耦。
可能這里有人還看不懂為什么通過第三方實現兩個類的依賴關系,就可以減少代碼的耦合度。實現兩個類的依賴關系,有三種普通注入方式,分為構造函數的注入、屬性注入、接口注入。
1
2
3
4
5
6
7
8
public class MovieFinder
{
...
}
1 構造函數注入(Contructor Injection)
MovieLister就只依賴於我們定義的MovieFinder接口,而不依賴於MovieFinder的實現了。
public class MovieLister {
private MovieFinder finder;
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
...
}
2 setter注入
類似的,我們可以增加一個setter函數來傳入創建好的MovieFinder對象,這樣同樣可以避免在MovieFinder中hard init這個對象。
1
public class MovieLister {
s...
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
}
3 接口注入
接口注入使用接口來提供setter方法,其實現方式如下。
首先要創建一個注入使用的接口。
1
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
之后,我們讓MovieLister實現這個接口。
7
class MovieLister implements InjectFinder {
...
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
...
}
以上三種注入方式,雖然實現了解耦,但多余了很多代碼來實例化MovieFinder,MovieLister和MovieFinder兩個類並沒有完全解耦,那如果將注入方式交給第三方呢?通過bean的注解,想調用時直接通過注解注入,揮之即來用之即去,這就是IOC的創建的初衷。
2、所以通過注解注入bean,就是實例化依賴類的方式,這也是為什么要將@Service和@Repository放到實現類上面而不是接口類上面,接口只是一個規范,需要各種實現類去實現這個接口,我們要用的就是這些實用類的方法。
3、注入的方式有@Recource和@Autowired
@Resource的作用相當於@Autowired,只不過@Autowired按byType自動注入,而@Resource默認按 byName自動注入罷了。
@Resource有兩個屬性是比較重要的,分別是name和type,spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。@Resource裝配順序
如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常。
如果指定了name,則從上下文中查找名稱(id匹配的bean進行裝配,找不到則拋出異常。
如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常。
如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配,如果沒有匹配,則回退為一個原始類型(UserDao)進行匹配,如果匹配則自動裝配。
當指定了@service的name值時, 在@Resource中要么不指示,如果指示的話,則要與之相對應。
當沒有指定@service的name值是,在@Resource中隨意。但是前提是,實現該接口的只有這一個類。
所以,建議是最好在@service和@Resoure中同時指定名稱,並且做到一一對應。
如果采用@Autowired來注解,則同樣無需指定name屬性,若是實現該接口有多個類,則需要通過@Qualifier來做區分
例:UserService、UserService2是實現IuserService的兩個實現類
類中@Service的注解分別是
@Service("userService1")
public class UserService implements IuserService {}
@Service("userService2")
public class UserService2 implements IuserService {}
那么在TestMethod中測試方法,使用接口IuserService時,使用的@Autowired來標注時,需要使用注解@Qualifier來做區分
@Autowired
@Qualifier("userService2")
private IuserService userService;
@Resource(name="loginService")
private LoginService loginService;
@Autowired(required=false)@Qualifier("loginService")
private LoginService loginService;
兩個的區別:
(1).@Autowired 與@Resource都可以用來裝配bean. 都可以寫在字段上,或寫在setter方法上;
(2).@Autowired 默認按類型裝配,默認情況下必須要求依賴對象必須存在,如果要允許null值,可以設
置它的required屬性為false,如:@Autowired(required=false) .
如果我們想使用名稱裝配可以結合 @Qualifier注解進行使用;
(3).@Resource(這個注解屬於J2EE的),默認安裝名稱進行裝配,名稱可以通過name屬性進行指定,如果沒
有指定name屬性,當注解寫在字段上時,默認取字段名進行安裝名稱查找,如果注解寫在setter方法上默認取屬
性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝 配。但是需要注意的是,如果name屬性一旦指
定,就只會按照名稱進行裝配。
為什么spring注入接口正確而注入接口的實現
原因所在:出現如果直接注入實現類會出現沒有對應的bean,因為我們通過實現類來繼承的接口,然而,必須使用jdk提供的動態代理放法,而不使用接口直接對實現類進行注入,則為cglib的注入,而不能既繼承接口又使用實現類來注入的方式,這樣兩種代理類都是沒有辦法使用的。
解決方案:1.直接通過jdk去生成動態代理類,(原理要求必須實現接口)
2.通過cglib去實現接口,直接使用代理類,而不能實現接口。
, 報錯原因: 直接注入實現類是不符合spring自己的設計規范的;
2, spring依賴注入設計思想就是利用java的多態特性,減少耦合,實現在配置文件中通過配置,實現不用更改java硬編碼,達到功能切換的目的, 所以注入的只能是接口,然后配置文件中切換其實現類;
3,注解出現后,多是在java文件中用注解注入,方便省事,而且一般來說,spring帶了一種設計思想,但實際上在配置文件中真正需要切換的並不多,所以為了方便,又使用了注解這種硬編碼;
4, 沒有什么設計是萬能的,根據實現情況來決定,一接口對應一個實現類的,直接用注解吧,真到了需要多個實現的時候,注解可以取注入的別名來指定實現類,也可以像以前一樣配置在XML中, 並不沖突
Spring動態注入的時候,如果一個類實現了一個接口,則需要利用到動態代理。
為了保持行為的一致性,代理類和委托類通常會實現相同的接口,所以在訪問者看來兩者沒有絲毫的區別。通過代理類這中間一層,能有效控制對委托類對象的直接訪問,也可以很好地隱藏和保護委托類對象,同時也為實施不同控制策略預留了空間,從而在設計上獲得了更大的靈活性。Java動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。
因為JDK生成的最終真正的代理類,它繼承自Proxy並實現了我們定義的接口,在實現接口方法的內部,通過反射調用了實現類的invoke方法。
為什么在CategoryController類中 @Auto明明注解在CategoryService 這個接口上 而注入的卻是CategoryServiceImpl這個實現類
因為: (自動裝配實現了CategoryService接口的的實例,只有CategoryServiceImpl實現了CategoryService接口,所以就會注入CategoryServiceImpl)
這種自動裝配 @Autowired 還是@Resource在裝配或者注入的時候都是先是實例化后再進行的 第一步都是先實例化
這里他要實例化一個接口是不可能的 所以要找到他的實現類 實例化他的實現類
源碼分析,好好看看
https://blog.csdn.net/mack415858775/article/details/47721909
---------------------
作者:半壁江山009
來源:CSDN
原文:https://blog.csdn.net/qq_31963719/article/details/79458002
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
什么要把DAO作為接口 再用impl類來實現?