溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

好程序員Java干貨分享Spring框架之IOC原理

發(fā)布時(shí)間:2020-08-14 05:31:13 來(lái)源:ITPUB博客 閱讀:180 作者:好程序員IT 欄目:編程語(yǔ)言

好程序員 Java 干貨分享 Spring 框架之 IOC 原理, 前言:Spring 框架是我們進(jìn)行企業(yè)級(jí)開(kāi)發(fā)的最常用框架,本章我們將了解 Spring 框架,并學(xué)習(xí) Spring IOC 特性以及 IOC 的實(shí)現(xiàn)原理:注解和反射。

Spring 框架簡(jiǎn)介

   Spring 是一種輕量級(jí)的控制反轉(zhuǎn)( IOC )和面向切面編程( AOP )的容器框架,能夠?yàn)槠髽I(yè)級(jí)開(kāi)發(fā)提供一站式服務(wù)。

   Spring 的優(yōu)點(diǎn)有

   1. 方便解耦,簡(jiǎn)化開(kāi)發(fā)

  通過(guò) Spring 提供的 IoC 容器,我們可以將對(duì)象之間的依賴關(guān)系交由 Spring 進(jìn)行控制,避免硬編碼所造成的過(guò)度程序耦合。有了 Spring ,用戶不必再為單實(shí)例模式類、屬性文件解析等這些很底層的需求編寫代碼,可以更專注于上層的應(yīng)用。

   2.AOP 編程的支持

  通過(guò) Spring 提供的 AOP 功能,方便進(jìn)行面向切面的編程,許多不容易用傳統(tǒng) OOP 實(shí)現(xiàn)的功能可以通過(guò) AOP 輕松應(yīng)付。

   3. 聲明式事務(wù)的支持

  在 Spring 中,我們可以從單調(diào)煩悶的事務(wù)管理代碼中解脫出來(lái),通過(guò)聲明式方式靈活地進(jìn)行事務(wù)的管理,提高開(kāi)發(fā)效率和質(zhì)量。

   4. 方便程序的測(cè)試

  可以用非容器依賴的編程方式進(jìn)行幾乎所有的測(cè)試工作,在 Spring 里,測(cè)試不再是昂貴的操作,而是隨手可做的事情。例如: Spring 對(duì) Junit4 支持,可以通過(guò)注解方便的測(cè)試 Spring 程序。

   5. 方便集成各種優(yōu)秀框架

   Spring 不排斥各種優(yōu)秀的開(kāi)源框架,相反, Spring 可以降低各種框架的使用難度, Spring 提供了對(duì)各種優(yōu)秀框架(如 Struts,Hibernate 、 Hessian Quartz )等的直接支持。

   6. 降低 Java EE API 的使用難度

   Spring 對(duì)很多難用的 Java EE API (如 JDBC JavaMail ,遠(yuǎn)程調(diào)用等)提供了一個(gè)薄薄的封裝層,通過(guò) Spring 的簡(jiǎn)易封裝,這些 Java EE API 的使用難度大為降低。

  

Spring 的組成

好程序員Java干貨分享Spring框架之IOC原理

   Spring Core Spring  框架的核心。 Spring 其它組件都依賴于核心組件,主要通過(guò) BeanFactory 提供 IOC 等服務(wù)。

   Spring Context Sprin 上下文是一個(gè)配置文件,向  Spring 框架提供上下文信息。 Spring  上下文包括企業(yè)服務(wù),例如 JNDI 、 EJB 、電子郵件、國(guó)際化、校驗(yàn)和調(diào)度功能。

   Spring AOP :通過(guò)配置管理特性, Spring AOP  模塊直接將面向切面的編程功能集成到了  Spring  框架中。

   Spring ORM Spring  框架插入了若干個(gè) ORM 框架,從而提供了  ORM  的對(duì)象關(guān)系工具,其中包括 JDO 、 Hibernate iBatisSQL Map 。所有這些都遵從  Spring  的通用事務(wù)和  DAO  異常層次結(jié)構(gòu)。

   Spring DAO:  DAO 抽象層提供了有意義的異常層次結(jié)構(gòu),可用該結(jié)構(gòu)來(lái)管理異常處理和不同數(shù)據(jù)庫(kù)供應(yīng)商拋出的錯(cuò)誤消息。異常層次結(jié)構(gòu)簡(jiǎn)化了錯(cuò)誤處理,并且極大地降低了需要編寫的異常代碼數(shù)量(例如打開(kāi)和關(guān)閉連接)。 Spring DAO  的面向  JDBC  的異常遵從通用的  DAO  異常層次結(jié)構(gòu)。

   Spring Web:  Web  上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于  Web  的應(yīng)用程序提供了上下文。所以, Spring 框架支持與  Jakarta Struts  的集成。 Web  模塊還簡(jiǎn)化了處理多部分請(qǐng)求以及將請(qǐng)求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?

   Spring Web MVC:  為  web  應(yīng)用提供了模型視圖控制( MVC )和  REST Web  服務(wù)的實(shí)現(xiàn)。 Spring  的  MVC  框架可以使領(lǐng)域模型代碼和  web  表單完全地分離,且可以與  Spring  框架的其它所有功能進(jìn)行集成。

  

IOC DI

   IOC Inverse Of Control )是控制反轉(zhuǎn)的意思,作用是降低對(duì)象之間的耦合度。

  一般情況下我們直接在對(duì)象內(nèi)部通過(guò) new 進(jìn)行創(chuàng)建對(duì)象,是程序主動(dòng)去創(chuàng)建依賴對(duì)象;而 IoC 是有專門一個(gè)容器來(lái)創(chuàng)建這些對(duì)象,即由 Ioc 容器來(lái)控制對(duì)象的創(chuàng)建;這樣就是由容器來(lái)控制對(duì)象,而不是由我們的對(duì)象來(lái)控制,這樣就完成了控制反轉(zhuǎn)。

   DI(Dependency Injection )即“依賴注入”:是組件之間依賴關(guān)系由容器在運(yùn)行期決定,形象的說(shuō),即由容器動(dòng)態(tài)的將某個(gè)依賴關(guān)系注入到組件之中。依賴注入的目的并非為軟件系統(tǒng)帶來(lái)更多功能,而是為了提升組件重用的頻率,并為系統(tǒng)搭建一個(gè)靈活、可擴(kuò)展的平臺(tái)。通過(guò)依賴注入機(jī)制,我們只需要通過(guò)簡(jiǎn)單的配置,而無(wú)需任何代碼就可指定目標(biāo)需要的資源,完成自身的業(yè)務(wù)邏輯,而不需要關(guān)心具體的資源來(lái)自何處,由誰(shuí)實(shí)現(xiàn)。

  

IOC 的原理:注解 + 反射

下面的案例講解了 IOC 的原理,模擬為電腦配置不同的 CPU 和內(nèi)存, CPU AMD INTEL 兩種,內(nèi)存有 DDR8G DDR16G 兩種

  1. /**
  2. * CPU 接口
  3. */
  4. public interface Cpu {
  5. void run();
  6. }
  7. /**
  8. 內(nèi)存接口
  9. */
  10. public interface Memory {
  11. void read();
  12. void write();
  13. }
  14. /**
  15. * AMD CPU
  16. */
  17. public class AMDCpu implements Cpu {
  18. public void run() {
  19. System.out.println("AMD CPU 正在運(yùn)行 ....");
  20. }
  21. }
  22. /**
  23. * Intel CPU
  24. */
  25. public class IntelCpu implements Cpu{
  26. public void run() {
  27. System.out.println("Intel CPU 正在運(yùn)行 ....");
  28. }
  29. }
  30. /**
  31. * DDR8G 的內(nèi)存
  32. */
  33. public class DDR8GMemory implements Memory {
  34. public void read() {
  35. System.out.println(" 使用 DDR8G 的內(nèi)存讀取數(shù)據(jù) ....");
  36. }
  37. public void write() {
  38. System.out.println(" 使用 DDR8G 的內(nèi)存寫入數(shù)據(jù) ....");
  39. }
  40. }
  41. /**
  42. * DDR16G 的內(nèi)存
  43. */
  44. public class DDR16GMemory implements Memory {
  45. public void read() {
  46. System.out.println(" 使用 DDR16G 的內(nèi)存讀取數(shù)據(jù) ....");
  47. }
  48. public void write() {
  49. System.out.println(" 使用 DDR16G 的內(nèi)存寫入數(shù)據(jù) ....");
  50. }
  51. }
  52. public class TestComputer {
  53. @Test
  54. public void testComputer(){
  55. // 硬編碼方式創(chuàng)建對(duì)象
  56. Computer computer = new Computer();
  57. Cpu cpu = new IntelCpu();
  58. Memory memory = new DDR16GMemory();
  59. computer.setCpu(cpu);
  60. computer.setMemory(memory);
  61. computer.start();
  62. }
  63. }

 

上面是使用硬編碼方式創(chuàng)建電腦的 CPU 和內(nèi)存屬性,代碼和具體的子類緊密耦合,不利于后期的維護(hù)和擴(kuò)展。

修改的思路是:不由讓程序主動(dòng)創(chuàng)建去創(chuàng)建 CPU 和內(nèi)存對(duì)象,而是通過(guò)注解方式標(biāo)記 CPU 和內(nèi)存的類型,使用反射將 CPU 和內(nèi)存的對(duì)象注入到電腦的屬性中。

添加代碼:

  1. /**
  2. 電腦組件的注解
  3. */
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target(ElementType.FIELD)
  6. public @interface MyComponent {
  7. /**
  8. 組件類型
  9. * @return
  10. */
  11. Class componentClass();
  12. }
  13. /**
  14. 電腦類
  15. */
  16. public class Computer {
  17. @MyComponent(componentClass = IntelCpu.class)
  18. private Cpu cpu;
  19. @MyComponent(componentClass = DDR8GMemory.class)
  20. private Memory memory;
  21. ....}
  22. public class TestComputer {
  23. @Test
  24. public void testComputer(){
  25. // 通過(guò)反射和注解,將 cpu memory 屬性注入進(jìn)去
  26. try {
  27. // 獲得 Computer 類型
  28. Class<Computer> computerClass = Computer.class;
  29. // 創(chuàng)建 Computer 對(duì)象
  30. Computer computer = computerClass.newInstance();
  31. // 獲得 Computer 對(duì)象的屬性
  32. Field[] fields = computerClass.getDeclaredFields();
  33. // 遍歷屬性
  34. for(Field field : fields){
  35. // 獲得屬性上定義的 MyComponent 注解
  36. MyComponent anno = field.getDeclaredAnnotation(MyComponent.class);
  37. // 獲得配置的組件類型
  38. Class aClass = anno.componentClass();
  39. // 創(chuàng)建該組件的對(duì)象
  40. Object comp = aClass.newInstance();
  41. // 調(diào)用 set 方法賦值給屬性
  42. String name = field.getName();
  43. name = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
  44. // 通過(guò)方法名和參數(shù)類型獲得方法
  45. Method method = computerClass.getDeclaredMethod(name, field.getType());
  46. // 調(diào)用方法
  47. method.invoke(computer,comp);
  48. }
  49. // 啟動(dòng)電腦
  50. computer.start();
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }

程序如上面修改后,后期如果需要修改電腦的配置,只需要修改注解配置的類型,就可以注入不同的電腦組件,這樣就降低了代碼間的耦合性,維護(hù)代碼變得比較簡(jiǎn)單。

  @MyComponent(componentClass = AMDCpu.class)

    private Cpu cpu;

 

  @MyComponent(componentClass = DDR16GMemory.class)

   private Memory memory;

 

總結(jié)

IOC (控制反轉(zhuǎn))是 Spring 最重要的原理,它將創(chuàng)建對(duì)象的主動(dòng)權(quán)交給 Spring 容器, Spring 程序只需要進(jìn)行一些配置,就可以使用不同的對(duì)象,極大的降低了代碼耦合性,提高了程序的靈活性, IOC 的實(shí)現(xiàn)原理是反射機(jī)制。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI