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

SpringIoC與SpringDI詳解

 更新時間:2025年03月15日 11:06:53   作者:鴿鴿程序猿  
本文介紹了Spring框架中的IoC(控制反轉(zhuǎn))和DI(依賴注入)概念,以及如何在Spring中使用這些概念來管理對象和依賴關(guān)系,感興趣的朋友一起看看吧

一、IoC與DI

名詞解釋:

  • spring是一個裝了眾多工具對象的IoC容器。
  • IoC思想:對象交給Spring管理,就是IoC思想。
  • IoC:Inversion of Control,控制反轉(zhuǎn)。

控制權(quán)反轉(zhuǎn),需要某個對象時, 傳統(tǒng)開發(fā)模式中需要??通過 new 創(chuàng)建對象, 現(xiàn)在不需要再進(jìn)?創(chuàng)建, 把創(chuàng)建對象的任務(wù)交給容器(IoC容器. Spring是?個IoC容器, 所以有時Spring 也稱為Spring容器), 程序中只需要依賴注? (Dependency Injection, DI)就可以了.

1.1 IoC

實現(xiàn)下面的需求:

在傳統(tǒng)的實現(xiàn)中,我們將每個模塊當(dāng)成一個類:

public class NewCarExample {
	 public static void main(String[] args) {
	 	Car car = new Car();
	 	car.run();
	 }
 /**
 * 汽?對象 
 */
 static class Car {
 	private Framework framework;
 	public Car() {
	 	 framework = new Framework();
		 System.out.println("Car init....");
	 }
	 public void run(){
	 	System.out.println("Car run...");
	 }
 }
 /**
 * ??類 
 */
 static class Framework {
	 private Bottom bottom;
	 public Framework() {
		 bottom = new Bottom();
		 System.out.println("Framework init...");
	 }
 }
 /**
 * 底盤類 
 */
 static class Bottom {
 	private Tire tire;
	public Bottom() {
		this.tire = new Tire();
		System.out.println("Bottom init...");
	 }
 }
 /**
 * 輪胎類 
 */
 static class Tire {
 // 尺? 
	 private int size;
	 public Tire(){
	 	this.size = 17;
	 	System.out.println("輪胎尺?:" + size);
	 }
	 }
}

但是如上面的代碼,如果我們要修改一個參數(shù),會導(dǎo)致整個調(diào)用鏈都跟著修改。

我們?yōu)榻鉀Q上面耦合度過高,可以采取:
把由??創(chuàng)建的下級類,改為傳遞的?式(也就是注?的?式),
每次調(diào)整只需要調(diào)整對應(yīng)那個類的代碼即可。
這樣?論底層類如何變化,整個調(diào)?鏈?zhǔn)遣?做任何改變的。

public class IocCarExample {
	 public static void main(String[] args) {
		 Tire tire = new Tire(20);
		 Bottom bottom = new Bottom(tire);
		 Framework framework = new Framework(bottom);
		 Car car = new Car(framework);
		 car.run();
 	}
	 static class Car {
		 private Framework framework;
		 public Car(Framework framework) {
		 	this.framework = framework;
			System.out.println("Car init....");
	 	}
		 public void run() {
		 	System.out.println("Car run...");
		 }
 	}
	 static class Framework {
		 private Bottom bottom;
		 public Framework(Bottom bottom) {
			this.bottom = bottom;
		 	System.out.println("Framework init...");
		 }
 	}
	 static class Bottom {
		 private Tire tire;
		 public Bottom(Tire tire) {
			 this.tire = tire;
			 System.out.println("Bottom init...");
		 }
	 }
	 static class Tire {
		 private int size;
		 public Tire(int size) {
		 	this.size = size;
		 	System.out.println("輪胎尺?:" + size);
		 }
	 }
}

1.2 DI

DI: Dependency Injection(依賴注?)
容器在運(yùn)?期間, 動態(tài)的為應(yīng)?程序提供運(yùn)?時所依賴的資源,稱之為依賴注?。

就像上面調(diào)用關(guān)系中:

二、IoC與DI的使用

Spring 是?個 IoC(控制反轉(zhuǎn))容器,作為容器, 那么它就具備兩個最基礎(chǔ)的功能:
• 存
• 取
Spring 容器 管理的主要是對象, 這些對象, 我們稱之為"Bean". 我們把這些對象交由Spring管理, 由 Spring來負(fù)責(zé)對象的創(chuàng)建和銷毀. 我們程序只需要告訴Spring, 哪些需要存, 以及如何從Spring中取出對象

我們實現(xiàn)這樣的功能,主要靠兩個注解:

  • Service層及Dao層的實現(xiàn)類,交給Spring管理: 使?注解: @Component
  • 在Controller層 和Service層 注?運(yùn)?時依賴的對象: 使?注解 @Autowired

像把前面的圖書管理系統(tǒng)的BookController重構(gòu)。
BookController類:

package com.example.project.controller;
import com.example.project.model.BookInfo;
import com.example.project.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequestMapping("/book")
@RestController
@Component
public class BookController {
    @Autowired
    private BookService bookService;
    @RequestMapping("/getList")
    public List<BookInfo> getList() {
        return bookService.getList();
    }
}

BookService類:

package com.example.project.service;
import com.example.project.dao.BookDao;
import com.example.project.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class BookService {
    @Autowired
    BookDao bookDao ;
    public List<BookInfo> getList() {
        List<BookInfo> books = new ArrayList<>();
        books = bookDao.mockData();
        for (BookInfo book:
                books) {
            if(book.getStatus() == 1) {
                book.setStatusCN("可借閱");
            } else {
                book.setStatusCN("不可借閱");
            }
        }
        return books;
    }
}

BookDao類:

package com.example.project.dao;
import com.example.project.model.BookInfo;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Component
public class BookDao {
    public List<BookInfo> mockData() {
        List<BookInfo> books = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            BookInfo book = new BookInfo();
            book.setId(i);
            book.setBookName("書籍" + i);
            book.setAuthor("作者" + i);
            book.setCount(i * 5 + 3);
            book.setPrice(new BigDecimal(new Random().nextInt(100)));
            book.setPublish("出版社" + i);
            book.setStatus(1);
            books.add(book);
        }
        return books;
    }
}

可以看到在類的調(diào)用之間,我們是使用的注解,將類作為另一個類的成員。不用自己去new實例。

三、IoC詳解

3.1 Bean的存儲

Bean在上面我們也說了,就是Spring管理起來的對象。

實現(xiàn)將對象交給Spring管理,
共有兩類注解類型可以:

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

3.2 @Controller(控制器存儲)

先使用@Controller將類存儲:

package com.example.springioc.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    public void hello() {
        System.out.println("Hello");
    }
}

從Spring容器中獲取對象:

先獲取Spring上下?對象

從Spring上下?中獲取對象

package com.example.springioc.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
    //先獲取Spring上下?對象 
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class,args);
        //從Spring上下?中獲取對象
        UserController userController = context.getBean(UserController.class);
        userController.hello();
    }
}

3.3 獲取Bean對象

獲取Bean對象主要是ApplicationContext 類下的getBean方法,有下圖中重載。

使用五大類注解讓Spring管理Bean對象的默認(rèn)取名方式如下官方文檔

  • 將類名轉(zhuǎn)換為小駝峰形式。UserController -》 userController
  • 當(dāng)前面是兩個即多個大寫字母連在一起,Bean對象名就是類名。USController -》 USController

Bean對象名也可以使用注解指定名稱,在使用五大注解加上括號即可。栗子: @Controller("name")
使用如下:

package com.example.springioc.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class,args);
        UserController bean1 = context.getBean(UserController.class);
        bean1.hello();
        UserController bean2 = (UserController) context.getBean("userController");
        bean2.hello();
        UserController bean3 =  context.getBean("userController", UserController.class);
        bean3.hello();
    }
}

3.4 @Service(服務(wù)存儲)

使用就加上@Service注解,拿到Bean對象方法不變。

package com.example.springioc.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    void print() {
        System.out.println("do Service");
    }
}

3.5 @Repository(倉庫存儲)

使用就加上@Repository 注解,拿到Bean對象方法不變。

package com.example.springioc.service;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
    void print() {
        System.out.println("do Repository");
    }
}

3.6 @Component(組件存儲)

使用就加上@Component 注解,拿到Bean對象方法不變。

package com.example.springioc.service;
import org.springframework.stereotype.Component;
@Component
public class UserComponent {
    void print() {
        System.out.println("do Component");
    }
}

3.7 @Configuration(配置存儲)

使用就加上@Configuration注解,拿到Bean對象方法不變。

package com.example.springioc.service;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfiguration {
    void print() {
        System.out.println("do Configuration");
    }
}

3.8 五大注解區(qū)別

@Controller @Service @Repository @Configuration這四個注解都是@Component注解的衍生注解。

分這么多注解就是為了更好地分層(邊界在使用中也沒非常清晰):

  • @Controller代表控制層。接收參數(shù)返回響應(yīng),控制層一定要使用@Controller
  • @Service代表服務(wù)層
  • @Repository代表數(shù)據(jù)層
  • @Configuration代表配置層
  • @Component代表組件層

3.9 ?法注解@Bean

使用:

package com.example.springioc.controller;
import com.example.springioc.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    @Bean
    public User user() {
        return new User("zhangsan",11);
    }
    public void hello() {
        System.out.println("Hello");
    }
}
package com.example.springioc.controller;
import com.example.springioc.model.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class,args);
        User bean1 = (User) context.getBean("user");
        System.out.println(bean1.getName());
    }
}

注意事項:

  • 使用@Bean注解默認(rèn)方法名就是管理的Bean對象名。
  • @Bean對象重命名可以直接加括號@Bean("name1"),還可以使用name屬性@Bean(name = "name1"),還可以使用value屬性@Bean(value = "name1"),并且可以傳String數(shù)組。

  • @Bean注解必須搭配五大類注解使用。
  • 當(dāng)方法有參數(shù)的時候,Spring會從容器中根據(jù)參數(shù)類型去找,是否有這個類型的對象,如果沒有,或者有多個不唯一都會報錯,有唯一一個就會拿這個對象賦值。

四、Spring掃描路徑

Spring默認(rèn)的掃描路徑是啟動類所在路徑及其子路徑。
當(dāng)我們要掃描其它路徑的時候,可以使用注解@ComponentScan("需要掃描路徑"),可以傳數(shù)組。
其實不怎么用這個注解,直接啟動類放在所有需要掃描的路徑的最上層包下即可。

五、DI詳解

依賴注?是?個過程,是指IoC容器在創(chuàng)建Bean時, 去提供運(yùn)?時所依賴的資源,?資源指的就是對象。

依賴注?, Spring給我們提供了三種?式:

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

5.1屬性注入@Autowired

屬性注?是使? @Autowired 注解實現(xiàn)的
注意事項:

  • 注入的對象必須是容器中已經(jīng)有的,也就是使用五大類注解交給Spring管理的。
  • @Autowired不能修飾final修飾的成員。

使用:

package com.example.springioc.controller;
import com.example.springioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    @Autowired
    private UserService us;
    public void hello() {
        System.out.println("Hello");
        us.print();
    }
}
package com.example.springioc;
import com.example.springioc.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class,args);
        UserController bean = context.getBean(UserController.class);
        bean.hello();
    }
}

打印結(jié)果為
Hello
do Service、

5.2 構(gòu)造方法注入

直接使用構(gòu)造函數(shù),將上面代碼改成如下也可以使用。

package com.example.springioc.controller;
import com.example.springioc.service.UserService;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    private UserService us;
    public UserController(UserService us) {
        this.userService = us;
    }
    public void hello() {
        System.out.println("Hello");
        us.print();
    }
}

注意事項:

  • 當(dāng)只有一個構(gòu)造函數(shù)的時候,直接可以注入。
  • 當(dāng)有兩個及以上構(gòu)造函數(shù)的時候,Spring無法辨別使用哪一個構(gòu)造函數(shù)注入,需要在使用的構(gòu)造函數(shù)前加上@Autowired注解。
  • 只能在一個構(gòu)造方法上加上@Autowired注解。

5.3 setter方法注入

直接加上set方法,加上@Autowired注解,將上面代碼改成如下也可以使用。

package com.example.springioc.controller;
import com.example.springioc.service.UserService;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    private UserService us;
    @Autowired
    public void setUserService(UserService us) {
        this.us = us;
    }
    public void hello() {
        System.out.println("Hello");
        us.print();
    }
}

注意事項:

  • set方法必須加上@Autowired注解,可以給多個set方法使用注解。
  • 不能修飾final修飾的成員的set方法。

優(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)?,就有被修改的?險

5.4 @Autowired注解問題及解決

當(dāng)一個類交給Spring多個對象后,使用@Autowired注解,會無法分辨。

package com.example.springioc.service;
import com.example.springioc.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    @Bean
    public User u1(String name) {
        return new User(name,11);
    }
    @Bean
    public User u2() {
        return new User("lisi",18);
    }
    @Bean
    public String name () {
        return "zhangsan";
    }
    public void print() {
        System.out.println("do Service");
    }
}
package com.example.springioc.controller;
import com.example.springioc.model.User;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    @Resource(name = "u1")
    private User user;
    public void hello() {
        System.out.println("Hello");
        System.out.println(user.toString());
    }
}

報錯信息:

解決方法:
提供了以下?種注解解決:

  • @Primary
  • @Qualifier
  • @Resource

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

 @Bean
 @Primary
    public String name () {
        return "zhangsan";
    }

使?@Qualifier注解:指定當(dāng)前要注?的bean對象。在@Qualifier的value屬性中,指定注?的bean的名稱,必須與@Autowired一起用。例如上面代碼:

@Autowired
@Qualifier("u1")
    private User user;

使?@Resource注解:是按照bean的名稱進(jìn)?注?。通過name屬性指定要注?的bean的名稱。@Resource是JDK提供的注解。
例如上面代碼:

@Resource(name = "u2")
    private User user;

@Autowired工作流程

到此這篇關(guān)于SpringIoC與SpringDI的文章就介紹到這了,更多相關(guān)SpringIoC與SpringDI內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論