欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring實現(xiàn)IoC和DI的方法詳解

 更新時間:2024年08月05日 09:25:53   作者:luming.02  
IoC全稱Inversion of Control (控制反轉(zhuǎn)) ,這里的控制其實是控制權(quán)的意思,可以理解為對象的獲取權(quán)力和方式發(fā)生了發(fā)轉(zhuǎn),DI依賴注?是?個過程,是指IoC容器在創(chuàng)建Bean時, 去提供運?時所依賴的資源,?資源指的就是對象,本文介紹了Spring實現(xiàn)IoC和DI的方法

一.Spring中的IoC

IoC全稱Inversion of Control (控制反轉(zhuǎn)) ,這里的控制其實是控制權(quán)的意思。可以理解為對象的獲取權(quán)力和方式發(fā)生了發(fā)轉(zhuǎn)。也就是說,當(dāng)需要某個對象時,傳統(tǒng)開發(fā)模式中需要??通過 new 創(chuàng)建對象;而IoC的思想則不一樣,IoC旨在把創(chuàng)建對象的任務(wù)交給外部的容器,程序中只需要引入容器里存放的需要的對象即可。這個容器一般被稱為:IoC容器。

其實IoC我們在前?已經(jīng)使?了,我們在前?講到,在類上?添加 @RestController 和 @Controller 注解,就是把這個對象交給Spring管理,Spring 框架啟動時就會加載該類,把對象交給Spring管理,這就是Spring中的IoC思想。Spring對于IoC的實現(xiàn)主要是通過工廠設(shè)計模式+反射來實現(xiàn)的,當(dāng)我們需要某個對象的時候,只需要將創(chuàng)建對象的任務(wù)交給容器,在程序中只需要調(diào)用(注入)即可。

前?我們提到IoC控制反轉(zhuǎn),就是將對象的控制權(quán)交給Spring的IOC容器,由IOC容器創(chuàng)建及管理對象。那么在Spring程序中,我們該如何通過代碼來實現(xiàn)IoC呢?

Spring框架為了更好的服務(wù)應(yīng)用程序,提供了倆類注解來實現(xiàn)將對象集中管理創(chuàng)建:

  • 類注解:@Controller、@Service、@Repository、@Component、@Configuration
  • 方法注解:@Bean

@Controller

使? @Controller 存儲 bean 的代碼如下所?:

@Controller // 將對象存儲到 Spring 中
public class UserController {
    public void sayHi(){
        System.out.println("hi,UserController...");
    }
}

如何觀察這個對象已經(jīng)存在Spring容器當(dāng)中了呢? 我們可以通過啟動類中的getBean方法來得到Spring中管理的Bean。

@SpringBootApplication
public class IoCdemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(IoCdemoApplication.class, args);
        UserController bean = context.getBean(UserController.class);
        bean.sayHi();
    }
}

在控制臺即可觀察到輸出:

但是一旦將@Controller注釋掉,程序就會報錯找不到這個Bean,這就說明了使用@Controller確實是可以將該類對象交給Spring進(jìn)行管理

@Service

@Service
public class UserService {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

 還是來獲取一下這個對象,看看結(jié)果如何

ConfigurableApplicationContext context = SpringApplication.run(IoCdemoApplication.class, args);
UserService bean = context.getBean(UserService.class);
bean.sayHi("CSDN");

如果注釋掉@Service就會報錯,因此可以證實@Service可以將類對象交給Spring進(jìn)行管理

后續(xù)的三個注解如果進(jìn)行相同方式的驗證都會得到一樣的結(jié)果,這里就不再贅述 

@Repository

@Repository
public class UserRepository {
    public void sayHi() {
        System.out.println("Hi, UserRepository~");
    }
}

@Component

@Component
public class UserComponent {
    public void sayHi() {
        System.out.println("Hi, UserComponent~");
    }
}

@Configuration

@Configuration
public class UserConfiguration {
    public void sayHi() {
        System.out.println("Hi,UserConfiguration~");
    }
}

那么既然這么多注解干的都是同一件事,為什么還非要分出這么多注解呢?

類注解之間的區(qū)別

這個也是和咱們前?講的應(yīng)?分層是呼應(yīng)的,不同的注解標(biāo)識著不同的信息,這些注解可以讓程序員看到類注解之后,就能直接了解當(dāng)前類的?途。

  • @Controller:控制層, 接收請求, 對請求進(jìn)?處理, 并進(jìn)?響應(yīng)
  • @Servie:業(yè)務(wù)邏輯層, 處理具體的業(yè)務(wù)邏輯
  • @Repository:數(shù)據(jù)訪問層,也稱為持久層. 負(fù)責(zé)數(shù)據(jù)訪問操作
  • @Configuration:配置層. 處理項?中的?些配置信息

這和每個省/市都有??的?牌號是?樣的。?牌號都是唯?的,標(biāo)識?個?輛的。但是為什么還需要設(shè)置不同的?牌開頭呢??如陜西的?牌號就是:陜X:XXXXXX,北京的?牌號:京X:XXXXXX,甚??個省不同的縣區(qū)也是不同的,?如西安就是,陜A:XXXXX,咸陽:陜B:XXXXXX,寶雞,陜C:XXXXXX,?樣。

這樣做的好處除了可以節(jié)約號碼之外,更重要的作?是可以直觀的標(biāo)識?輛?的歸屬地.

對于一般的開發(fā)我們通過不同的注解去確認(rèn)它是哪一層的代碼,這樣更方面上下層進(jìn)行調(diào)用

類注解之間的聯(lián)系

細(xì)心的朋友可能發(fā)現(xiàn)了,上述的注解中少了一個@Component注解,我們不妨打開每個注解的源碼看看。


我們會發(fā)現(xiàn)上述4個注解中都有@Component注解,這說明它們本?就是屬于 @Component 的 "?類"。@Component 是?個元注解,也就是說可以注解其他類注解,如 @Controller、@Service 、@Repository 等, 這些注解被稱為 @Component 的衍?注解。

@Controller、@Service 和 @Repository ?于更具體的?例(分別在控制層, 業(yè)務(wù)邏輯層, 持久化層),在開發(fā)過程中,如果你要在業(yè)務(wù)邏輯層使? @Component 或 @Service,顯然@Service是更好的選擇。

諸如@Configuration,見名知意就是用來標(biāo)記配置相關(guān)的,比如我們想用Redis的數(shù)據(jù)庫,在使用Redis之前需要對Redis數(shù)據(jù)庫的密碼或者庫做一些配置,配置好了之后我們需要將這個配置類交給Spring管理方便我們在別的地方直接訪問Redis數(shù)據(jù)庫,這時使用@Configuration就是很好的選擇。

?如杯?有喝?杯、刷?杯等,但是我們更傾向于在?常喝?時使??杯,洗漱時使?刷?杯。

方法注解@Bean

類注解是添加到某個類上的, 但是存在兩個問題

  • 使?外部包?的類, 沒辦法添加類注解
  • ?個類, 需要多個對象, ?如多個數(shù)據(jù)源

比如我們想通過引入第三方的工具類去操作數(shù)據(jù)庫,我們想將這個類交給Spring管理方便我們進(jìn)行二次開發(fā),但是由于第三方包只能讀取不能寫入的情況,就會陷入進(jìn)退倆難的情況。

@Bean 同上述類注解的功能一樣,都是將標(biāo)記的對象交給Spring進(jìn)行管理,但在 Spring 框架的設(shè)計中,?法注解 @Bean 要配合類注解才能將對象正常的存儲到 Spring 容器中,如下代碼所?:

@Component
public class BeanConfig {
    @Bean
    public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
}

我們也可以通過設(shè)置name屬性給Bean對象進(jìn)行重命名

@Bean(name = {"u1","user1"})

二.DI——Dependency Injection(依賴注入)

依賴注?是?個過程,是指IoC容器在創(chuàng)建Bean時, 去提供運?時所依賴的資源,?資源指的就是對象,在之前程序案例中,我們使?了 @Autowired 這個注解,完成了依賴注?的操作。

關(guān)于依賴注?,Spring也給我們提供了三種?式:

  • 屬性注?(Field Injection)
  • 構(gòu)造?法注?(Constructor Injection)
  • Setter 注?(Setter Injection)

屬性注入

屬性注?是使? @Autowired 實現(xiàn)的,將 Service 類注?到 Controller 類中。

Service 類的實現(xiàn)代碼如下:

import org.springframework.stereotype.Service;
 
@Service
public class UserService {
    public void sayHi() {
        System.out.println("Hi,UserService");
    }
}

Controller 類的實現(xiàn)代碼如下: 

@Controller
public class UserController {
    //注??法1: 屬性注?
    @Autowired
    private UserService userService;
    
    public void sayHi() {
        System.out.println("hi,UserController...");
        userService.sayHi();
    }
}

構(gòu)造方法注入

構(gòu)造?法注?是在類的構(gòu)造?法中實現(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();
    }
}

如果類只有?個構(gòu)造?法,那么 @Autowired 注解可以省略;如果類中有多個構(gòu)造?法,那么需要添加上 @Autowired 來明確指定到底使?哪個構(gòu)造?法。

Setter注入

Setter 注?和屬性的 Setter ?法實現(xiàn)類似,只不過在設(shè)置 set ?法的時候需要加上 @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)缺點

屬性注?

優(yōu)點:

  • 簡潔,使??便

缺點:

  • 只能?于 IoC 容器,如果是? IoC 容器不可?,并且只有在使?的時候才會出現(xiàn) NPE(空指針異常)
  • 不能注??個Final修飾的屬性

構(gòu)造函數(shù)注入(Spring 4.X推薦)

優(yōu)點:

  • 可以注?final修飾的屬性
  • 注?的對象不會被修改
  • 依賴對象在使?前?定會被完全初始化,因為依賴是在類的構(gòu)造?法中執(zhí)?的,?構(gòu)造?法是在類加載階段就會執(zhí)?的?法.
  • 通?性好, 構(gòu)造?法是JDK?持的, 所以更換任何框架,他都是適?的

缺點:

  • 注?多個對象時, 代碼會?較繁瑣

Setter注入(Spring 3.X推薦)

優(yōu)點:

  • ?便在類實例之后, 重新對該對象進(jìn)?配置或者注?

缺點:

  • 不能注??個Final修飾的屬性
  • 注?對象可能會被改變, 因為setter?法可能會被多次調(diào)?, 就有被修改的?險

@Autowired存在問題

當(dāng)同?類型存在多個bean時, 使?@Autowired會存在問題

@Component
public class BeanConfig {
    @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;
    }
}
@Controller
public class UserController {
    
    @Autowired
    private UserService userService;
    //注?user
    @Autowired
    private User user;
    public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
        System.out.println(user);
    }
}

程序會出現(xiàn)無法正確找到Bean的報錯

如何解決上述問題呢?Spring提供了以下?種解決?案:

  • @Primary
  • @Qualifier
  • @Resource

使?@Primary注解:當(dāng)存在多個相同類型的Bean注?時,加上@Primary注解,來確定默認(rèn)的實現(xiàn)

@Component
public class BeanConfig {
    @Primary //指定該bean為默認(rèn)bean的實現(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注解:指定當(dāng)前要注?的bean對象。 在@Qualifier的value屬性中,指定注?的bean的名稱(@Qualifier注解不能單獨使?,必須配合@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注解:是按照bean的名稱進(jìn)?注?。通過name屬性指定要注?的bean的名稱。并且由于@Resource是由JDK提供的,因此在其他框架下也有可延展性。

@Controller
public class UserController {
    @Resource(name = "user2")
    private User user;
    public void sayHi(){
        System.out.println("hi,UserController...");
        System.out.println(user);
    }
}

@Autowired 是spring框架提供的注解,?@Resource是JDK提供的注解

@Autowired 默認(rèn)是按照類型注?,?@Resource是按照名稱注?。相?于 @Autowired 來說 @Resource ?持更多的參數(shù)設(shè)置,例如 name 設(shè)置,根據(jù)名稱獲取 Bean

以上就是Spring實現(xiàn)IoC和DI的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring實現(xiàn)IoC和DI的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論