?? 博客主頁:從零開始的-CodeNinja之路
? 收錄文章:Java Spring IoC&DI :探索Java Spring中控制反轉(zhuǎn)和依賴注入的威力,增強(qiáng)靈活性和可維護(hù)性
??歡迎大家點(diǎn)贊??評(píng)論??收藏?文章
前提小知識(shí):高內(nèi)聚低耦合
我們一下要學(xué)習(xí)的內(nèi)容都是為了實(shí)現(xiàn)?內(nèi)聚低耦合來進(jìn)行的
軟件設(shè)計(jì)原則:?內(nèi)聚低耦合.
?內(nèi)聚指的是:?個(gè)模塊中各個(gè)元素之間的聯(lián)系的緊密程度,如果各個(gè)元素(語句、程序段)之間的聯(lián)
系程度越?,則內(nèi)聚性越?,即"?內(nèi)聚"。
低耦合指的是:軟件中各個(gè)層、模塊之間的依賴關(guān)聯(lián)程序越低越好。修改?處代碼,其他模塊的代碼
改動(dòng)越少越好.
?內(nèi)聚低耦合?盾嗎?
不?盾,?內(nèi)聚指的是?個(gè)模塊中各個(gè)元素之間的聯(lián)系的緊密程度,低耦合指的是各個(gè)模塊之間的緊
密程度
這就好??個(gè)企業(yè),包含很多部?,各個(gè)部?之間的關(guān)聯(lián)關(guān)系要盡可能的?,?個(gè)部?發(fā)?問題,要盡
可能對(duì)降低對(duì)其他部?的影響,就是耦合.但是部?內(nèi)部員?關(guān)系要盡量緊密,遇到問題?起解決,克
服.這叫做內(nèi)聚.
?如鄰?鄰居,樓上漏?,樓下遭殃,就是耦合.家庭?個(gè)成員?病,其他成員幫忙照顧,就叫內(nèi)聚.
?個(gè)家庭內(nèi)部的關(guān)系越緊密越好,?個(gè)家庭盡可能少的影響另?個(gè)家庭,就是低耦合.
簡(jiǎn)單來說:就是在未來的工作中寫出的代碼盡量集中在一個(gè)路徑中,但是每個(gè)程序與其它程序的關(guān)聯(lián)度很低,以至于一個(gè)文件出錯(cuò)了并不影響其它程序的正常運(yùn)行.
一. IOC
1.1 什么是IOC?
IoC是Spring的核?思想,也是常?的?試題,那什么是IoC呢?
IoC:InversionofControl(控制反轉(zhuǎn)),也就是說Spring是?個(gè)"控制反轉(zhuǎn)"的容器.
什么是控制反轉(zhuǎn)呢?也就是控制權(quán)反轉(zhuǎn).什么的控制權(quán)發(fā)?了反轉(zhuǎn)?獲得依賴對(duì)象的過程被反轉(zhuǎn)了
也就是說,當(dāng)需要某個(gè)對(duì)象時(shí),傳統(tǒng)開發(fā)模式中需要??通過new創(chuàng)建對(duì)象,現(xiàn)在不需要再進(jìn)?創(chuàng)
建,把創(chuàng)建對(duì)象的任務(wù)交給容器,程序中只需要依賴注?(DependencyInjection,DI)就可以了.
我們??句更具體的話來概括Spring,那就是:Spring是包含了眾多?具?法的IoC容器
簡(jiǎn)單點(diǎn)來說:就是通過IOC的內(nèi)置注解將被注解的內(nèi)容放到Spring的大池子里,方便后續(xù)的調(diào)用(這樣子應(yīng)該很好理解)
1.2 IOC的實(shí)現(xiàn)
舉個(gè)栗子:比如傳統(tǒng)的造車過程是一級(jí)級(jí)的調(diào)用,如下:
以上程序的問題是:當(dāng)最底層代碼改動(dòng)之后,整個(gè)調(diào)?鏈上的所有代碼都需要修改.程序的耦合度?常?(修改?處代碼,影響其他處的代碼修改)
經(jīng)過IOC實(shí)現(xiàn)后的流程圖如下:
而IOC的目標(biāo)就是為了降低耦合度,對(duì)于上面的例子來說就是將汽車每個(gè)部件的生產(chǎn)都交給第三方來處理,不讓他們之間有聯(lián)系,也就降低了耦合度
我們發(fā)現(xiàn)了?個(gè)規(guī)律,通?程序的實(shí)現(xiàn)代碼,類的創(chuàng)建順序是反的,傳統(tǒng)代碼是Car控制并創(chuàng)建了
Framework,F(xiàn)ramework創(chuàng)建并創(chuàng)建了Bottom,依次往下,?改進(jìn)之后的控制權(quán)發(fā)?的反轉(zhuǎn),不再
是使??對(duì)象創(chuàng)建并控制依賴對(duì)象了,?是把依賴對(duì)象注?將當(dāng)前對(duì)象中,依賴對(duì)象的控制權(quán)不再由
當(dāng)前類控制了.
這樣的話,即使依賴類發(fā)?任何改變,當(dāng)前類都是不受影響的,這就是典型的控制反轉(zhuǎn),也就是IoC的
實(shí)現(xiàn)思想。
1.3 IOC容器的優(yōu)點(diǎn)
資源不由使?資源的雙?管理,?由不使?資源的第三?管理,這可以帶來很多好處。第?,資源集
中管理,實(shí)現(xiàn)資源的可配置和易管理。第?,降低了使?資源雙?的依賴程度,也就是我們說的耦合
度。
- 資源集中管理:IoC容器會(huì)幫我們管理?些資源(對(duì)象等),我們需要使?時(shí),只需要從IoC容器中去取
就可以了 - 我們?cè)趧?chuàng)建實(shí)例的時(shí)候不需要了解其中的細(xì)節(jié),降低了使?資源雙?的依賴程度,也就是耦合度.
Spring就是?種IoC容器,幫助我們來做了這些資源管理.
1.4 IOC的存儲(chǔ)
在之前的??案例中,要把某個(gè)對(duì)象交給IOC容器管理,需要在類上添加?個(gè)注解: @Component
?Spring框架為了更好的服務(wù)web應(yīng)?程序,提供了更豐富的注解.
共有兩類注解類型可以實(shí)現(xiàn):
- 類注解:@Controller、@Service、@Repository、@Component、@Configuration.
- ?法注解:@Bean.
接下來我們分別來看
@Controller(控制器存儲(chǔ))
使?@Controller存儲(chǔ)bean的代碼如下所?:
@Controller // 將對(duì)象存儲(chǔ)到 Spring 中
public class UserController {
public void sayHi(){
System.out.println("hi,UserController...");
}
}
@Service(服務(wù)存儲(chǔ))
使?@Service存儲(chǔ)bean的代碼如下所?:
@Service// 將對(duì)象存儲(chǔ)到 Spring 中
public class UserService {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
@Repository(倉庫存儲(chǔ))
使? @Repository 存儲(chǔ)bean的代碼如下所?:
@Repository
public class UserRepository {
public void sayHi() {
System.out.println("Hi, UserRepository~");
}
}
@Component(組件存儲(chǔ))
使?@Component存儲(chǔ)bean的代碼如下所?:
@Component
public class UserComponent {
public void sayHi() {
System.out.println("Hi, UserComponent~");
}
}
@Configuration(配置存儲(chǔ))
使?@Configuration存儲(chǔ)bean的代碼如下所?:
@Configuration
public class UserConfiguration {
public void sayHi() {
System.out.println("Hi,UserConfiguration~");
}
}
@Bean (方法注解)
類注解是添加到某個(gè)類上的同時(shí)?法注解要配合類注解使?,但是存在兩個(gè)問題:
- 使?外部包?的類,沒辦法添加類注解
- ?個(gè)類,需要多個(gè)對(duì)象,?如多個(gè)數(shù)據(jù)源
這種場(chǎng)景,我們就需要使??法注解 @Bean
我們先來看看?法注解如何使?:
?法注解要配合類注解使?
@Component
public class BeanConfig {
@Bean
public User user(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
1.5 IOC注解總結(jié)概括
-
@Controller:控制層,接收請(qǐng)求,對(duì)請(qǐng)求進(jìn)?處理,并進(jìn)?響應(yīng).
-
@Servie:業(yè)務(wù)邏輯層,處理具體的業(yè)務(wù)邏輯.
-
@Repository:數(shù)據(jù)訪問層,也稱為持久層.負(fù)責(zé)數(shù)據(jù)訪問操作
-
@Configuration:配置層.處理項(xiàng)?中的?些配置信息.
-
@Component:其它4大類注解的父類
-
@Bean:方法注解,將一個(gè)方法交給Spring管理,同時(shí)要與類注解一起搭配使用
其實(shí)這些注解??都有?個(gè)注解 @Component ,說明它們本?就是屬于 @Component 的"?類".@Component 是?個(gè)元注解,也就是說可以注解其他類注解,如 @Controller , @Service ,
@Repository 等.這些注解被稱為 @Component 的衍?注解.
@Controller , @Service 和 @Repository ?于更具體的?例(分別在控制層,業(yè)務(wù)邏輯層,持
久化層),在開發(fā)過程中,如果你要在業(yè)務(wù)邏輯層使? @Component 或@Service,顯然@Service是更
好的選擇
二. DI
2.1 什么是DI?
DI:DependencyInjection(依賴注?)
容器在運(yùn)?期間,動(dòng)態(tài)的為應(yīng)?程序提供運(yùn)?時(shí)所依賴的資源,稱之為依賴注?。
程序運(yùn)?時(shí)需要某個(gè)資源,此時(shí)容器就為其提供這個(gè)資源.
從這點(diǎn)來看,依賴注?(DI)和控制反轉(zhuǎn)(IoC)是從不同的?度的描述的同?件事情,就是指通過
引?IoC容器,利?依賴關(guān)系注?的?式,實(shí)現(xiàn)對(duì)象之間的解耦。
上述代碼中,是通過構(gòu)造函數(shù)的?式,把依賴對(duì)象注?到需要使?的對(duì)象中的
可以說,DI是IoC的?種實(shí)現(xiàn)
2.2 DI的方法使用
依賴注?是?個(gè)過程,是指IoC容器在創(chuàng)建Bean時(shí),去提供運(yùn)?時(shí)所依賴的資源,?資源指的就是對(duì)象.
在上?程序案例中,我們使?了 @Autowired 這個(gè)注解,完成了依賴注?的操作.
簡(jiǎn)單來說,就是把對(duì)象取出來放到某個(gè)類的屬性中.
在?些?章中,依賴注?也被稱之為"對(duì)象注?",“屬性裝配”,具體含義需要結(jié)合?章的上下?來理解
關(guān)于依賴注?,Spring也給我們提供了三種?式:
- 屬性注?(FieldInjection)
- 構(gòu)造?法注?(ConstructorInjection)
- Setter注?(SetterInjection)
屬性注入
屬性注?是使? @Autowired 實(shí)現(xiàn)的,將Service類注?到Controller類中.
Service類的實(shí)現(xiàn)代碼如下:
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
構(gòu)造方法注入
構(gòu)造?法注?是在類的構(gòu)造?法中實(shí)現(xiàn)注?,如下代碼所?:
@Controller
public class UserController2 {
//注??法2: 構(gòu)造?法
private UserService userService;
@Autowired
public UserController2(UserService userService) {
this.userService = userService;
}
public void sayHi(){
System.out.println("hi,UserController2...");
userService.sayHi();
}
}
注意事項(xiàng):如果類只有?個(gè)構(gòu)造?法,那么@Autowired注解可以省略;如果類中有多個(gè)構(gòu)造?法,
那么需要添加上@Autowired來明確指定到底使?哪個(gè)構(gòu)造?法。
Setter注入
Setter注?和屬性的Setter?法實(shí)現(xiàn)類似,只不過在設(shè)置set?法的時(shí)候需要加上@Autowired注
解,如下代碼所?:
@Controller
public class UserController3 {
//注??法3: Setter?法注?
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHi(){
System.out.println("hi,UserController3...");
userService.sayHi();
}
}
三種注入優(yōu)缺點(diǎn)分析
- 屬性注?
優(yōu)點(diǎn):簡(jiǎn)潔,使??便;
缺點(diǎn):
- 只能?于IoC容器,如果是?IoC容器不可?,并且只有在使?的時(shí)候才會(huì)出現(xiàn)NPE(空指針異常)
- 不能注??個(gè)Final修飾的屬性
- 構(gòu)造函數(shù)注?
優(yōu)點(diǎn):
- 可以注?final修飾的屬性
- 注?的對(duì)象不會(huì)被修改
- 依賴對(duì)象在使?前?定會(huì)被完全初始化,因?yàn)橐蕾囀窃陬惖臉?gòu)造?法中執(zhí)?的,?構(gòu)造?法 是在類加載階段就會(huì)執(zhí)?的?法.
- 通?性好,構(gòu)造?法是JDK?持的,所以更換任何框架,他都是適?的
缺點(diǎn):
注?多個(gè)對(duì)象時(shí),代碼會(huì)?較繁瑣
- Setter注?
優(yōu)點(diǎn):?便在類實(shí)例之后,重新對(duì)該對(duì)象進(jìn)?配置或者注?
缺點(diǎn):
- 不能注??個(gè)Final修飾的屬性
- 注?對(duì)象可能會(huì)被改變,因?yàn)閟etter?法可能會(huì)被多次調(diào)?,就有被修改的?險(xiǎn).
2.3 @Autowired存在的問題
當(dāng)同?類型存在多個(gè)bean時(shí),使?@Autowired會(huì)存在問題
報(bào)錯(cuò)的原因是,?唯?的Bean對(duì)象。
如何解決上述問題呢?Spring提供了以下?種解決?案:
? @Primary
? @Qualifier
? @Resource
@Primary
使?@Primary注解:當(dāng)存在多個(gè)相同類型的Bean注?時(shí),加上@Primary注解,來確定默認(rèn)的實(shí)現(xiàn).
@Component
public class BeanConfig {
@Primary //指定該bean為默認(rèn)bean的實(shí)現(xiàn)
@Bean("u1")
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
@Qualifier
使?@Qualifier注解:指定當(dāng)前要注?的bean對(duì)象。在@Qualifier的value屬性中,指定注?的bean
的名稱。
? @Qualifier注解不能單獨(dú)使?,必須配合@Autowired使?
@Controller
public class UserController {
@Qualifier("user2") //指定bean名稱
@Autowired
private User user;
public void sayHi(){
System.out.println("hi,UserController...");
System.out.println(user);
}
}
@Resource
使?@Resource注解:是按照bean的名稱進(jìn)?注?。通過name屬性指定要注?的bean的名稱。
@Controller
public class UserController {
@Resource(name = "user2")
private User user;
public void sayHi(){
System.out.println("hi,UserController...");
System.out.println(user);
}
}
2.4 @Autowird的注入流程圖
常見?試題:
@Autowird與@Resource的區(qū)別
? @Autowired是spring框架提供的注解,?@Resource是JDK提供的注解
? @Autowired默認(rèn)是按照類型注?,?@Resource是按照名稱注?.相?于@Autowired來說,
@Resource?持更多的參數(shù)設(shè)置,例如name設(shè)置,根據(jù)名稱獲取Bean。
三. 總結(jié)
Java Spring框架中的IoC(Inversion of Control,控制反轉(zhuǎn))和DI(Dependency Injection,依賴注入)是框架的核心概念之一,它們旨在降低組件之間的耦合度,提高代碼的靈活性和可維護(hù)性。
-
控制反轉(zhuǎn)(IoC):在傳統(tǒng)的程序設(shè)計(jì)中,應(yīng)用程序控制程序的流程,即應(yīng)用程序負(fù)責(zé)實(shí)例化和管理對(duì)象之間的依賴關(guān)系。而在IoC容器中,控制權(quán)被轉(zhuǎn)移到容器,容器負(fù)責(zé)實(shí)例化對(duì)象并管理它們之間的依賴關(guān)系。這種控制權(quán)的轉(zhuǎn)移使得組件之間的耦合度降低,提高了代碼的靈活性和可測(cè)試性。
-
依賴注入(DI):依賴注入是IoC的一種實(shí)現(xiàn)方式,通過依賴注入,容器會(huì)將一個(gè)對(duì)象所依賴的其他對(duì)象注入到該對(duì)象中,而不是由對(duì)象自己去創(chuàng)建或查找依賴的對(duì)象。依賴注入可以通過構(gòu)造函數(shù)、屬性或者方法進(jìn)行注入,使得組件之間的依賴關(guān)系更加清晰、可控,同時(shí)也方便進(jìn)行單元測(cè)試和替換依賴。文章來源:http://www.zghlxwxcb.cn/news/detail-851804.html
總的來說,IoC和DI通過將控制權(quán)交給容器,實(shí)現(xiàn)了組件之間的解耦和松耦合,提高了代碼的可維護(hù)性、可測(cè)試性和可擴(kuò)展性,是Spring框架的核心特性之一。文章來源地址http://www.zghlxwxcb.cn/news/detail-851804.html
到了這里,關(guān)于Java Spring IoC&DI :探索Java Spring中控制反轉(zhuǎn)和依賴注入的威力,增強(qiáng)靈活性和可維護(hù)性的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!