国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

香港云服务器
服務(wù)器之家 - 編程語言 - JAVA教程 - 實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

2020-03-31 11:57haolloyin JAVA教程

這篇文章主要介紹了Java的Spring框架中的控制反轉(zhuǎn)和依賴注入,Spring是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下

近來總是接觸到 IoC(Inversion of Control,控制反轉(zhuǎn))、DI(Dependency Injection,依賴注入)等編程原則或者模式,而這些是著名 Java 框架 Spring、Struts 等的核心所在。針對此查了 Wikipedia 中各個條目,并從圖書館借來相關(guān)書籍,閱讀后有些理解,現(xiàn)結(jié)合書中的講解以及自己的加工整理如下:
 

eg1
問題描述:
開發(fā)一個能夠按照不同要求生成Excel或 PDF 格式的報表的系統(tǒng),例如日報表、月報表等等。
 
解決方案:
根據(jù)“面向接口編程”的原則,應(yīng)該分離接口與實現(xiàn),即將生成報表的功能提取為一個通用接口ReportGenerator,并提供生成 Excel 和 PDF格式報表的兩個實現(xiàn)類 ExcelGenerator 和 PDFGenerator,而客戶Client 再通過服務(wù)提供者 ReportService 獲取相應(yīng)的報表打印功能。
 
實現(xiàn)方法:
根據(jù)上面所述,得到如下類圖:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

代碼實現(xiàn):
 

01interface ReportGenerator {
02 public void generate(Table table);
03}
04  
05class ExcelGenerator implements ReportGenerator {
06 public void generate(Table table) {
07  System.out.println("generate an Excel report ...");
08 }
09}
10  
11class PDFGenerator implements ReportGenerator {
12 public void generate(Table table) {
13  System.out.println("generate an PDF report ...");
14 }
15}
16  
17class ReportService {
18 // 負責(zé)創(chuàng)建具體需要的報表生成器
19 private ReportGenerator generator = new PDFGenerator();
20 // private static ReportGenerator generator = new ExcelGenerator();
21   
22 public void getDailyReport(Date date) {
23  table.setDate(date);
24  // ...
25  generator.generate(table);
26 }
27   
28 public void getMonthlyReport(Month month) {
29  table.setMonth(month);
30  // ...
31  generator.generate(table);
32 }
33}
34  
35  
36public class Client {
37 public static void main(String[] args) {
38  ReportService reportService = new ReportService();
39  reportService.getDailyReport(new Date());
40  //reportService.getMonthlyReport(new Date());
41 }
42}

 
eg2 
問題描述:
如上面代碼中的注釋所示,具體的報表生成器由 ReportService 類內(nèi)部硬編碼創(chuàng)建,由此 ReportService 已經(jīng)直接依賴于 PDFGenerator 或 ExcelGenerator ,必須消除這一明顯的緊耦合關(guān)系。
 
解決方案:引入容器
引入一個中間管理者,也就是容器(Container),由其統(tǒng)一管理報表系統(tǒng)所涉及的對象(在這里是組件,我們將其稱為 Bean),包括 ReportService 和各個 XXGenerator 。在這里使用一個鍵-值對形式的 HashMap 實例來保存這些 Bean。
 
實現(xiàn)方法:
得到類圖如下:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

代碼實現(xiàn):

01class Container {
02 // 以鍵-值對形式保存各種所需組件 Bean
03 private static Map<String, Object> beans;
04   
05 public Container() {
06  beans = new HashMap<String, Object>();
07    
08  // 創(chuàng)建、保存具體的報表生起器
09  ReportGenerator reportGenerator = new PDFGenerator();
10  beans.put("reportGenerator", reportGenerator);
11    
12  // 獲取、管理 ReportService 的引用
13  ReportService reportService = new ReportService();
14  beans.put("reportService", reportService);
15 }
16   
17 public static Object getBean(String id) {
18  return beans.get(id);
19 }
20}
21  
22class ReportService {
23 // 消除緊耦合關(guān)系,由容器取而代之
24 // private static ReportGenerator generator = new PDFGenerator();
25 private ReportGenerator generator = (ReportGenerator) Container.getBean("reportGenerator");
26  
27 public void getDailyReport(Date date) {
28  table.setDate(date);
29  generator.generate(table);
30 }
31   
32 public void getMonthlyReport(Month month) {
33  table.setMonth(month);
34  generator.generate(table);
35 }
36}
37  
38public class Client {
39 public static void main(String[] args) {
40  Container container = new Container();
41  ReportService reportService = (ReportService)Container.getBean("reportService");
42  reportService.getDailyReport(new Date());
43  //reportService.getMonthlyReport(new Date());
44 }
45}

 
時序圖大致如下:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

效果:
如上面所示,ReportService 不再與具體的 ReportGenerator 直接關(guān)聯(lián),已經(jīng)用容器將接口和實現(xiàn)隔離開來了,提高了系統(tǒng)組件 Bean 的重用性,此時還可以使用配置文件在 Container 中實時獲取具體組件的定義。
 
eg3
問題描述:
然而,觀察上面的類圖,很容易發(fā)現(xiàn) ReportService 與 Container 之間存在雙向關(guān)聯(lián),彼此互相有依賴關(guān)系。并且,如果想要重用 ReportService,由于它也是直接依賴于單獨一個 Container 的具體查找邏輯。若其他容器具體不同的組件查找機制(如 JNDI),此時重用 ReportService 意味著需要修改 Container 的內(nèi)部查找邏輯。
 
解決方案:引入 Service Locator
再次引入一個間接層 Service Locator,用于提供組件查找邏輯的接口,請看Wikipedia 中的描述 或者 Java EE 對其的描述1 、描述2 。這樣就能夠?qū)⒖赡茏兓狞c隔離開來。
 
實現(xiàn)方法:
類圖如下:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

代碼實現(xiàn):
 

01// 實際應(yīng)用中可以是用 interface 來提供統(tǒng)一接口
02class ServiceLocator {
03 private static Container container = new Container();
04   
05 public static ReportGenerator getReportGenerator() {
06  return (ReportGenerator)container.getBean("reportGeneraator");
07 }
08}
09  
10class ReportService {
11 private ReportGenerator reportGenerator = ServiceLocator.getReportGenerator();
12   
13 // ...
14}

 

eg4

問題描述:
然而,不管是引入 Container 還是使用 Service Locator ,ReportService 對于具體組件的查找、創(chuàng)建的方式都是‘主動'的,這意味著作為客戶的 ReportService 必須清楚自己需要的是什么、到哪里獲取、如何獲取。一下子就因為 What、Where、How 而不得不增加了具體邏輯細節(jié)。
 
例如,在前面‘引入Container '的實現(xiàn)方法中,有如下代碼: 

1class ReportService {
2 // 消除緊耦合關(guān)系,由容器取而代之
3 // private static ReportGenerator generator = new PDFGenerator();
4 // 通過 Container..getBean("reportGenerator") ‘主動'查找
5 private ReportGenerator generator = (ReportGenerator) Container
6   .getBean("reportGenerator");

 
在‘引入 Service Locator '的實現(xiàn)方法中,有如下代碼: 

01class ServiceLocator {
02 privatestatic Container container = new Container();
03 publicstatic ReportGenerator getReportGenerator() {
04  // 還是container.getBean(), 用了委托而已
05  return (ReportGenerator) container.getBean("reportGeneraator");
06 }
07}
08class ReportService {
09 // ReportService 最終還是‘主動'查找,委托給ServiceLocator 而已
10 private ReportGenerator reportGenerator = ServiceLocator.getReportGenerator();
11}

 
解決方案:
在這種情況下,變‘主動'為‘被動'無疑能夠減少 ReportService 的內(nèi)部知識(即查找組件的邏輯)。根據(jù)控制反轉(zhuǎn)(IoC)原則,可江此種拉(Pull,主動的)轉(zhuǎn)化成推(Push,被動的)的模式。
 
例如,平時使用的 RSS 訂閱就是Push的應(yīng)用,省去了我們一天好幾次登錄自己喜愛的站點主動獲取文章更新的麻煩。
 
而依賴注入(DI)則是實現(xiàn)這種被動接收、減少客戶(在這里即ReportService)自身包含復(fù)雜邏輯、知曉過多的弊病。
 
實現(xiàn)方法:
因為我們希望是‘被動'的接收,故還是回到 Container 的例子,而不使用 Service Locator 模式。由此得到修改后的類圖如下:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

而原來的類圖如下,可以對照著看一下,注意注釋的提示:

實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入

代碼實現(xiàn):
為了使例子能夠編譯、運行,并且稍微利用跟蹤代碼的運行結(jié)果來顯式整個類圖實例化、互相協(xié)作的先后順序,在各個類的構(gòu)造器中加入了不少已編號的打印語句,以及兩個無關(guān)緊要的類,有點啰唆,具體如下: 

01import java.util.Date;
02import java.util.HashMap;
03import java.util.Map;
04// 為了能夠編譯運行,多了兩個無關(guān)緊要的類
05class Month { }
06class Table {
07 publicvoid setDate(Date date) { }
08 publicvoid setMonth(Month month) { }
09}
10// ------------ 以下均無甚重要改變 ----------------- //
11interface ReportGenerator {
12 publicvoid generate(Table table);
13}
14class ExcelGenerator implements ReportGenerator {
15 public ExcelGenerator() {
16  System.out.println("2...開始初始化 ExcelGenerator ...");
17 }
18 publicvoid generate(Table table) {
19  System.out.println("generate an Excel report ...");
20 }
21}
22class PDFGenerator implements ReportGenerator {
23 public PDFGenerator() {
24  System.out.println("2...開始初始化 PDFGenerator ...");
25 }
26 publicvoid generate(Table table) {
27  System.out.println("generate an PDF report ...");
28 }
29}
30//------------ 以上均無甚重要改變 ----------------- //
31class Container {
32 // 以鍵-值對形式保存各種所需組件 Bean
33 privatestatic Map<String, Object> beans;
34 public Container() {
35  System.out.println("1...開始初始化 Container ...");
36  beans = new HashMap<String, Object>();
37  // 創(chuàng)建、保存具體的報表生起器
38  ReportGenerator reportGenerator = new PDFGenerator();
39  beans.put("reportGenerator", reportGenerator);
40  // 獲取、管理 ReportService 的引用
41  ReportService reportService = new ReportService();
42  // 注入上面已創(chuàng)建的具體 ReportGenerator 實例
43  reportService.setReportGenerator(reportGenerator);
44  beans.put("reportService", reportService);
45  System.out.println("5...結(jié)束初始化 Container ...");
46 }
47 publicstatic Object getBean(String id) {
48  System.out.println("最后獲取服務(wù)組件...getBean() --> " + id + " ...");
49  returnbeans.get(id);
50 }
51}
52  
53class ReportService {
54 // private static ReportGenerator generator = new PDFGenerator();
55 // 消除上面的緊耦合關(guān)系,由容器取而代之
56 // private ReportGenerator generator = (ReportGenerator) Container
57 //   .getBean("reportGenerator");
58 // 去除上面的“主動”查找,提供私有字段來保存外部注入的對象
59 private ReportGenerator generator;
60 // 以 setter 方式從外部注入
61 publicvoid setReportGenerator(ReportGenerator generator) {
62  System.out.println("4...開始注入 ReportGenerator ...");
63  this.generator = generator;
64 }
65  
66 private Table table = new Table();
67 public ReportService() {
68  System.out.println("3...開始初始化 ReportService ...");
69 }
70 publicvoid getDailyReport(Date date) {
71  table.setDate(date);
72  generator.generate(table);
73 }
74 publicvoid getMonthlyReport(Month month) {
75  table.setMonth(month);
76  generator.generate(table);
77 }
78}
79  
80publicclass Client {
81 publicstaticvoid main(String[] args) {
82  // 初始化容器
83  new Container();
84  ReportService reportService = (ReportService) Container
85    .getBean("reportService");
86  reportService.getDailyReport(new Date());
87  // reportService.getMonthlyReport(new Date());
88 }
89}

 
運行結(jié)果:

11...開始初始化 Container ...
22...開始初始化 PDFGenerator ...
33...開始初始化 ReportService ...
44...開始注入 ReportGenerator ...
55...結(jié)束初始化 Container ...
6 
7最后獲取服務(wù)組件...getBean() --> reportService ...
8generate an PDF report ...

 
注意:
1、根據(jù)上面運行結(jié)果的打印順序,可見代碼中加入的具體編號是合理的,模擬了程序執(zhí)行的流程,于是也就不再畫序列圖了。
2、注意該例子中對IoC、DI的使用,是以ReportService為客戶端(即組件需求者)為基點的,而代碼中的Client 類main()中的測試代碼才是服務(wù)組件的最終用戶,但它需要的不是組件,而是組件所具有的服務(wù)。
3、實際在Spring框剪中,初始化Container顯然不是最終用戶Client應(yīng)該做的事情,它應(yīng)該由服務(wù)提供方事先啟動就緒。
4、在最終用戶Client中,我們還是用到Container.getBean("reportService")來獲取事先已在Container的構(gòu)造函數(shù)中實例化好的服務(wù)組件。而在具體應(yīng)用中,通常是用XML等配置文件將可用的服務(wù)組件部署到服務(wù)器中,再由Container讀取該配置文件結(jié)合反射技術(shù)得以創(chuàng)建、注入具體的服務(wù)組件。
 
分析:
之前是由ReportService主動從Container中請求獲取服務(wù)組件,而現(xiàn)在是被動地等待Container注入(Inject,也就是Push)服務(wù)組件。控制權(quán)明顯地由底層模塊(ReportService 是組件需求者)轉(zhuǎn)移給高層模塊(Container 是組件提供者),也就是控制反轉(zhuǎn)了。
 

延伸 · 閱讀

精彩推薦
573
主站蜘蛛池模板: 91精品一区二区三区久久久久久 | 久久国产一区 | 色乱码一区二区三区网站 | 亚洲一区 日韩精品 中文字幕 | 免费成人激情视频 | 一区福利 | 久久综合九色综合欧美狠狠 | 国产成人精品一区二区三区视频 | 午夜久久久久 | 亚洲婷婷一区二区三区 | 一区国产精品 | 国产电影一区二区三区 | 亚洲成人三级 | av片在线观看 | 久久国产精品久久久久久久久久 | 国产一区二区av在线 | 欧美成人精品一区二区三区 | 国产精品二区一区二区aⅴ污介绍 | 羞羞网站免费观看 | 欧美视频网站 | 一区二区三区免费在线 | 日韩电影免费在线观看 | 日韩三级观看 | 久久久久久免费看 | 成人网在线观看 | 四虎影视永久免费观看 | 一区二区三区视频在线观看 | 国产日韩欧美精品 | 亚洲精品国产精品国自产在线 | 欧美一级片 | 99pao成人国产永久免费视频 | 欧美激情视频一区二区三区在线播放 | 成年人在线免费观看视频网站 | 五月激情综合网 | 97久久久 | 日本精品视频一区二区 | 日韩亚洲| 亚洲欧美中文日韩在线 | 成人aⅴ视频 | 不卡一二三区 | 色噜噜狠狠狠综合曰曰曰 |