JAVA CDI 學習- @Produces及@Disposes
上一節學習了注入Bean的生命週期,今天再來看看另一個話題: Bean的生產(@Produces)及銷燬(@Disposes),這有點象設計模式中的工廠模式。在正式學習這個之前,先來看一個場景:
基於web的db應用開發中,經常要在一個頁面上連線db,然後乾點啥,最後關閉連線。下面用之前二節前到的CDI技能來演練一下:
1、先建一個Connection的介面
1 package conn; 2 3 public interface Connection { 4 5 void connect(); 6 7 void closeConnection(); 8 9 String doSomething(); 10 11 }
Connection Interface
2、再來一個實現
1 package conn; 2 3 import javax.annotation.PostConstruct; 4 import javax.annotation.PreDestroy; 5 6 public class ConnectionImpl implements Connection { 7 /** 8 * Servlet建構函式呼叫後,會自動執行帶有@PostConstruct的方法 9 */ 10 @PostConstruct 11 private void initConn(){ 12 System.out.println("initConn is called..."); 13 connect(); 14 } 15 16 /** 17 * Servlet解除安裝前,會自動執行帶有@PreDestroy的方法 18 */ 19 @PreDestroy 20 private void destroyConn(){ 21 System.out.println("destroyConn is called..."); 22 closeConnection(); 23 } 24 25 @Override 26 public void connect() { 27 System.out.println("Connecting..."); 28 29 } 30 31 @Override 32 public void closeConnection() { 33 System.out.println("Closing connection..."); 34 35 } 36 37 @Override 38 public String doSomething() { 39 String msg = "do something..."; 40 System.out.println(msg); 41 return msg; 42 43 } 44 45 }
ConnectionImpl
注:留意一下@PostConstruct與@PreDestroy這二個特殊的註解。我們知道所有jsf/jsp頁面,最終執行時,實際上執行的是背後對應的Servlet,整個Servlet的生命週期在加入了這二個註解後,其執行順序如下:
所以,當ConnectionImpl最終被注入到Controller中時,會自動先呼叫initConn方法建立連線,在整個Request結束前,自動呼叫destroyConn關閉連線。
3、建立Controller類
1 package controller; 2 3 import javax.inject.Inject; 4 import javax.inject.Named; 5 6 import conn.Connection; 7 import conn.TestConnection; 8 9 @Named("Conn") 10 public class ConnectionController { 11 12 @Inject 13 private Connection connection; 14 15 public Connection getConnection() { 16 return connection; 17 } 18 19 }
ConnectionController
4、新建conn.xhtml用於顯示
1 html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""> 2 6 7 8Connection Test 9 10 11 #{Conn.connection.doSomething()} 12 13
conn.xhtml
eclipse裡部署到jboss下,瀏覽
跟預想的完全一樣! 條條道路通羅馬,解決問題的途徑往往不止一條,或許有些人不喜歡在ConnectionImpl裡參雜太多其它的職責(比如:自動開啟連線、自動關閉連線),可以考慮用CDI的produces及disposes.
5、建立ConnectionFactory
回想一下設計模式中的工廠模式,物件的建立(銷燬)通常放在一個單獨的工廠類來處理(單一職責原則),我們也來建一個工廠:
1 package conn; 2 3 import javax.enterprise.context.RequestScoped; 4 import javax.enterprise.inject.*; 5 6 public class ConnectionFactory { 7 8 @Produces 9 @RequestScoped 10 @MyConnection 11 public Connection getConn() { 12 System.out.println("ConnectionFactory.getConn is called..."); 13 Connection conn = new ConnectionImpl(); 14 conn.connect(); 15 return conn; 16 17 } 18 19 20 public void closeConn(@Disposes @MyConnection Connection conn) { 21 System.out.println("ConnectionFactory.closeConn is called..."); 22 conn.closeConnection(); 23 } 24 25 }
注:關注一下@Produces這個註解,這表示應用該註解的方法,是一個Bean的生成器(或理解成工廠的某些產品生產流水線),在需要Inject的時候,會自動透過該方法產生物件例項;而@Disposes註解,正好與@Produces對應,用於人道毀滅@Produces產生的物件,此消彼漲,這樣世界才會遵從守恆定律!
@RequestScoped不用多解釋了,表示工廠裡產生的Bean其生命週期僅存在於單次Http請求中。
but,just wait a minute,@MyConnection ? what is this ? why we need it ?
讓我們將思維方式,從人類大腦切換成計算機電腦的模式,ConnectionImpl繼承自Connection,對於系統來講,這二個是都是相容Connection型別的,在產生物件時,這還好說,因為目前Connection只有一個實現類ConnectionImpl,計算機可以足夠智慧的推斷出應該用ConnectionImpl來建立物件例項,但是物件銷燬的時候呢?這時傳入的引數型別是Connection介面型別,這時它並不知道該物件具體是何種實現?
所以,我們自己建立了一個@MyConnection註解,在@Produces與@Disposes上都應用該註解,這樣物件銷燬時,就能根據該註解精確的知道是要銷燬何種型別的哪個物件.
6、@MyConnection程式碼如下:
1 package conn; 2 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.Target; 5 6 import static java.lang.annotation.ElementType.FIELD; 7 import static java.lang.annotation.ElementType.TYPE; 8 import static java.lang.annotation.ElementType.METHOD; 9 import static java.lang.annotation.ElementType.PARAMETER; 10 import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 12 import javax.inject.Qualifier; 13 14 @Qualifier 15 @Retention(RUNTIME) 16 @Target({ FIELD, TYPE, METHOD, PARAMETER }) 17 public @interface MyConnection { 18 19 }
@MyConnection
7、修改ConnectionController
1 @Inject 2 @MyConnection 3 private Connection connection;
在原來的@Inject下,增加@MyConnection,否則Controller感受不到Factory的存在(系統將只是簡單的注入一個ConnectionImpl例項而已,不會自動建立連線/關閉連線),感興趣的同學可以先不加這個註釋,然後執行試試,體會一下
編譯、部署、執行,觀察Console的輸出:
Perfect!
8、@Produces當成資源池使用
@Produces還有一個用途,可以把一些其它地方需要用到的注入物件,統一放在一起先“生產”好,形成一個"資源池",在需要使用的地方,直接從池裡拿來用即可.
下面演示了這種用法:
8.1 先定義一個Product POJO類:
1 package model; 2 3 public class Product { 4 5 private String productName; 6 7 private String productNo; 8 9 public String getProductName() { 10 return productName; 11 } 12 13 public void setProductName(String productName) { 14 this.productName = productName; 15 } 16 17 public String getProductNo() { 18 return productNo; 19 } 20 21 public void setProductNo(String productNo) { 22 this.productNo = productNo; 23 } 24 25 @Override 26 public String toString() { 27 return productNo + "," + productName; 28 } 29 30 }
8.2 再建立一個Resocues.java,用來統一管理需要用到的資源
1 package resource; 2 3 import javax.enterprise.inject.Produces; 4 import javax.inject.Named; 5 6 import model.Product; 7 8 public class Resouces { 9 10 @Produces 11 @Named 12 public Product getNewProduct() { 13 Product product = new Product(); 14 product.setProductName("new product"); 15 product.setProductNo("000000"); 16 return product; 17 } 18 19 }
8.3 然後在頁面上就可以直接使用了
1 html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""> 2 7 8 9CDI Sample Test 10 11 #{newProduct.toString()} 12 13
注意:這裡我們並沒有任何的Controller,Resouces類本身也沒有使用@Named之類的註解,只是在方法getNewProduct上使用了 @Produces、 @Named,頁面上就可以直接使用資源池中的物件了.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4301/viewspace-2800927/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JAVA CDI @Inject基本用法Java
- java學習總結及心得體會Java
- Java-Stream流方法學習及總結Java
- JAVA學習筆記及知識積累Java筆記
- java學習路線及書籍下載Java
- java學習之道 --- 如何學習java?Java
- 在Java SE下測試CDI Bean和持久層 - relationJavaBean
- CDI元件技術(一)元件
- Java命令學習系列(零)——常見命令及Java Dump介紹Java
- Java 學習Java
- Java學習Java
- Java學習之反射機制及應用場景Java反射
- 新手如何學習Java——Java學習路線圖Java
- Olsnodes Produces CPU Spikes With Many Logs [ID 729349.1]
- Java學習之路 -- Java怎麼學?Java
- 《JAVA學習指南》學習筆記Java筆記
- 學習scala,java安裝jdk及jre的問題JavaJDK
- Java學習—java-RedisJavaRedis
- 深度學習及深度強化學習研修深度學習強化學習
- java學習之路Java
- Java學習自學Java
- Java學習方法Java
- Java學習:反射Java反射
- Java學習_反射Java反射
- 學習Java系列Java
- java學習6Java
- 如何學習JavaJava
- 學習java之路Java
- Java學習概要Java
- Java NIO 學習Java
- Java的學習Java
- Java反射學習Java反射
- java如何學習Java
- 學習Java: QueueJava
- java學習02Java
- java學習03Java
- java學習06Java
- java學習9.21Java