JAVA CDI @Inject基本用法
CDI(Contexts and Dependency Injection 上下文依賴注入),是JAVA官方提供的依賴注入實現,可用於Dynamic Web Module中,先給3篇老外的文章,寫得很不錯。
1、Java EE CDI Dependency Injection (@Inject) tutorial
2、Java EE CDI Producer methods tutorial
3、Java EE CDI bean scopes
如果不想啃洋文,也可以繼續往下看:
一、基本的Inject注入
1.1 在eclipse中先建立一個常規的maven Dynamic Web專案(不熟悉maven的,可以先看看這裡),下面是完整的專案截圖
裡面各package的程式碼,後面會給出。 專案的屬性中,注意有幾個屬性要勾上(預設情況下,應該已經自動勾上了),如下圖:
上圖右側的圓圈,其實就是CDI 1.0使用的先決條件。
Pom.xml的內容如下:
1 2 <!-- 3 JBoss, Home of Professional Open Source 4 Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual 5 contributors by the @authors tag. See the copyright.txt in the 6 distribution for a full listing of individual contributors. 7 8 Licensed under the Apache License, Version 2.0 (the "License"); 9 you may not use this file except in compliance with the License. 10 You may obtain a copy of the License at 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 --> 1820 4.0.0 21 22cnblogs 23cdi-web-sample 240.0.1-SNAPSHOT 25war 26cdi-web-sample 27A starter Java EE 6 webapp project for use on JBoss AS 7 / EAP 6, generated from the jboss-javaee6-webapp archetype 28 2930 31 37 3832 36Apache License, Version 2.0 33repo 34.html 3539 <!-- Explicitly declaring the source encoding eliminates the following 40 message: --> 41 <!-- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered 42 resources, i.e. build is platform dependent! --> 43 65 66 67UTF-8 44 45 <!-- JBoss dependency versions --> 467.4.Final 47 48 <!-- Define the version of the JBoss BOMs we want to import to specify 49 tested stacks. --> 501.0.7.Final 51 <!-- Alternatively, comment out the above line, and un-comment the line 52 below to use version 1.0.4.Final-redhat-4 which is a release certified to 53 work with JBoss EAP 6. It requires you have access to the JBoss EAP 6 54 maven repository. --> 55 <!--1.0.4.Final-redhat-4 > --> 56 57 <!-- other plugin versions --> 582.10 592.1.1 60 61 <!-- maven-compiler-plugin --> 621.6 631.6 6468 93 9469 <!-- JBoss distributes a complete set of Java EE 6 APIs including a Bill 70 of Materials (BOM). A BOM specifies the versions of a "stack" (or a collection) 71 of artifacts. We use this here so that we always get the correct versions 72 of artifacts. Here we use the jboss-javaee-6.0-with-tools stack (you can 73 read this as the JBoss stack of the Java EE 6 APIs, with some extras tools 74 for your project, such as Arquillian for testing) and the jboss-javaee-6.0-with-hibernate 75 stack you can read this as the JBoss stack of the Java EE 6 APIs, with extras 76 from the Hibernate family of projects) --> 77 9278 84org.jboss.bom 79jboss-javaee-6.0-with-tools 80${version.jboss.bom} 81pom 82import 8385 91org.jboss.bom 86jboss-javaee-6.0-with-hibernate 87${version.jboss.bom} 88pom 89import 9095 96 <!-- First declare the APIs we depend on and need for compilation. All 97 of them are provided by JBoss AS 7 --> 98 99 <!-- Import the CDI API, we use provided scope as the API is included in 100 JBoss AS 7 --> 101 203 204102 106 107 <!-- Import the Common Annotations API (JSR-250), we use provided scope 108 as the API is included in JBoss AS 7 --> 109javax.enterprise 103cdi-api 104provided 105110 114 115 <!-- Import the JAX-RS API, we use provided scope as the API is included 116 in JBoss AS 7 --> 117org.jboss.spec.javax.annotation 111jboss-annotations-api_1.1_spec 112provided 113118 122 123 <!-- Import the JPA API, we use provided scope as the API is included in 124 JBoss AS 7 --> 125org.jboss.spec.javax.ws.rs 119jboss-jaxrs-api_1.1_spec 120provided 121126 130 131 <!-- Import the EJB API, we use provided scope as the API is included in 132 JBoss AS 7 --> 133org.hibernate.javax.persistence 127hibernate-jpa-2.0-api 128provided 129134 138 139 <!-- JSR-303 (Bean Validation) Implementation --> 140 <!-- Provides portable constraints such as @Email --> 141 <!-- Hibernate Validator is shipped in JBoss AS 7 --> 142org.jboss.spec.javax.ejb 135jboss-ejb-api_3.1_spec 136provided 137143 153 154 <!-- Import the JSF API, we use provided scope as the API is included in 155 JBoss AS 7 --> 156org.hibernate 144hibernate-validator 145provided 146147 152148 151org.slf4j 149slf4j-api 150157 161 162 <!-- Now we declare any tools needed --> 163 164 <!-- Annotation processor to generate the JPA 2.0 metamodel classes for 165 typesafe criteria queries --> 166org.jboss.spec.javax.faces 158jboss-jsf-api_2.1_spec 159provided 160167 171 172 <!-- Annotation processor that raising compilation errors whenever constraint 173 annotations are incorrectly used. --> 174org.hibernate 168hibernate-jpamodelgen 169provided 170175 179 180 <!-- Needed for running tests (you may also use TestNG) --> 181org.hibernate 176hibernate-validator-annotation-processor 177provided 178182 186 187 <!-- Optional, but highly recommended --> 188 <!-- Arquillian allows you to test enterprise code such as EJBs and Transactional(JTA) 189 JPA from JUnit/TestNG --> 190junit 183junit 184test 185191 195 196org.jboss.arquillian.junit 192arquillian-junit-container 193test 194197 201 202org.jboss.arquillian.protocol 198arquillian-protocol-servlet 199test 200205 <!-- Maven will append the version to the finalName (which is the name 206 given to the generated war, and hence the context root) --> 207 226 227${project.artifactId} 208209 225210 217 <!-- The JBoss AS plugin deploys your war to a local JBoss AS container --> 218 <!-- To use, run: mvn package jboss-as:deploy --> 219maven-war-plugin 211${version.war.plugin} 212213 <!-- Java EE 6 doesn't require web.xml, Maven needs to catch up! --> 214 216false 215220 224org.jboss.as.plugins 221jboss-as-maven-plugin 222${version.jboss.maven.plugin} 223228 304229 <!-- The default profile skips all tests, though you can tune it to run 230 just unit tests based on a custom pattern --> 231 <!-- Seperate profiles are provided for running all tests, including Arquillian 232 tests that execute in the specified container --> 233 249 250default 234235 237true 236238 248239 247240 246maven-surefire-plugin 241${version.surefire.plugin} 242243 245true 244251 <!-- An optional Arquillian testing profile that executes tests in your 252 JBoss AS instance --> 253 <!-- This profile will start a new JBoss AS instance, and execute the 254 test, shutting it down when done --> 255 <!-- Run with: mvn clean test -Parq-jbossas-managed --> 256 265 266arq-jbossas-managed 257258 264259 263org.jboss.as 260jboss-as-arquillian-container-managed 261test 262267 <!-- An optional Arquillian testing profile that executes tests in a remote 268 JBoss AS instance --> 269 <!-- Run with: mvn clean test -Parq-jbossas-remote --> 270 279 280arq-jbossas-remote 271272 278273 277org.jboss.as 274jboss-as-arquillian-container-remote 275test 276281 <!-- When built in OpenShift the 'openshift' profile will be used when 282 invoking mvn. --> 283 <!-- Use this profile for any OpenShift specific customization your app 284 will need. --> 285 <!-- By default that is to put the resulting archive into the 'deployments' 286 folder. --> 287 <!-- > 288 302 303openshift 289290 301291 300292 299maven-war-plugin 293${version.war.plugin} 294295 298deployments 296ROOT 297
1.2 model包下,會建立Product類
1 package model; 2 3 public class Product { 4 5 private String productName; 6 7 private String productNo; 8 9 public String getProductNo() { 10 return productNo; 11 } 12 13 public void setProductNo(String productNo) { 14 this.productNo = productNo; 15 } 16 17 public String getProductName() { 18 return productName; 19 } 20 21 public void setProductName(String productName) { 22 this.productName = productName; 23 } 24 25 public String toString() { 26 return this.productName + " " + this.productNo; 27 28 } 29 }
這個類其實是打醬油的。
1.3 service包下,建一個ProductService介面
1 package service; 2 3 import model.Product; 4 5 public interface ProductService { 6 7 Product getNewProduct(); 8 9 }
1.4 service包下,再來幾個實現
1 package service; 2 3 import javax.inject.Inject; 4 5 import model.Product; 6 7 public abstract class BaseProductServiceImpl implements ProductService { 8 9 @Inject 10 protected Product product; 11 12 13 public abstract Product getNewProduct(); 14 }
這個是實現類的基類,注意這裡私有成員上打了一個註解@Inject,表示執行時將動態注入(例項化)一個Product
再來二個具體的實現類,BookProductServiceImpl生成"書籍"
1 package service; 2 3 import annotation.Book; 4 import model.Product; 5 6 @Book 7 public class BookProductServiceImpl extends BaseProductServiceImpl { 8 9 public Product getNewProduct() { 10 product.setProductName("論程式設計師的自我修養"); 11 product.setProductNo("ISBN 999"); 12 return product; 13 } 14 15 }
TelephoneProductServiceImpl生成“電話”
1 package service; 2 3 import annotation.Telephone; 4 import model.Product; 5 6 @Telephone 7 public class TeletephoneProductServiceImpl extends BaseProductServiceImpl { 8 9 public Product getNewProduct() { 10 product.setProductName("NOKIA LUMIA"); 11 product.setProductNo("920"); 12 return product; 13 } 14 }
可能有朋友注意到了,裡面用到了二個自己寫的註釋@Book和@Telephone,接下來會講到,這裡先忽略
1.5 controller包下,新增IndexController類
為了能跟JSF的前臺頁面互動,這裡需要新增一個Controller
1 package controller; 2 3 import javax.faces.bean.ManagedBean; 4 import javax.inject.Inject; 5 6 import annotation.*; 7 import service.*; 8 9 @ManagedBean(name = "Index") 10 public class IndexController { 11 12 @Inject 13 @Book 14 private ProductService bookProductService; 15 16 @Inject 17 @Telephone 18 private ProductService telephoneProductService; 19 20 public ProductService getBookProductService() { 21 return bookProductService; 22 } 23 24 public ProductService getTelephoneProductService() { 25 return telephoneProductService; 26 } 27 28 } 29 IndexController
好了,一下子搞了這麼多程式碼,先停下來消化一下,這裡我們模擬了分層架構:
model - 代表了業務模型層(本例中,為了簡單起見,沒有細分 業務模型、實體模型、以及web中的ViewModel)
service - 代表了服務層(為了簡單起見,我們把介面+實現都放在一起了,實際中,可能會把這二個分開來)
controller - 這是web層MVC中的控制器層
當然,為了能展示最終的效果,我們會在後面加一個頁面做為View層來提供UI
1.6 webapp下,新建一個index.xhtml檔案,內容如下:
1 html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""> 2 6 7 8 9 Book: 10
#{Index.bookProductService.newProduct.toString()} 11
12
Telephone: 13
#{Index.telephoneProductService.newProduct.toString()} 14
頁面裡幾乎沒啥程式碼,就是呼叫IndexController例項中的getBookProductService、getTelephoneProductService方法,進而得到相應的"服務實現類例項",最終輸出產品資訊
1.7 Inject用在什麼地方了?
a) 頁面顯示時,IndexController裡,bookProductService和telephoneProductService這二個私有成員上,都加了@Inject註解,所以執行時,這二個成員都能被例項化,但是問題來了,它們都是ProductService的介面型別,而這個介面有二個具體的實現(BookProductServiceImpl和TeletephoneProductServiceImpl),最終執行時,應該實現化哪一個呢?
關鍵在於另一個註解@Book和@Telephone,觀察一下:BookProductServiceImpl類上我們也加了@Book,而TeletephoneProductServiceImpl上加了@Telephone,這樣正好可以跟IndexControll中這二個私成成員的註釋“匹配”上,所以最終系統知道私有成員bookProductService應該被例項化成BookProductServiceImpl,telephoneProductService被例項化成TeletephoneProductServiceImpl
@Book和@Telephone的程式碼如下:
1 package annotation; 2 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 6 import javax.inject.Qualifier; 7 8 @Qualifier 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface Book { 11 12 }
1 package annotation; 2 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 import javax.inject.Qualifier; 6 7 @Qualifier 8 @Retention(RetentionPolicy.RUNTIME) 9 public @interface Telephone { 10 11 }
b) BaseProductServiceImpl中,在私成成員product上加了@Inject,這樣執行時,能自動例項化Product物件
1.8 執行結果
jboss中部署後,瀏覽 或
1.9 Method(方法)注入及Constructor(構造器)注入
剛才我們看到的都是在Field(成員)上注入,除了這種方式,也可以在Method或Constructor上注入
1 private Product product ; 2 3 /** 4 * 演示在方法上使用@Inject注入 5 * @param p 6 */ 7 @Inject 8 public void setProduct(Product p){ 9 product = p; 10 } 11 12 public Product getProduct(){ 13 return product; 14 }
上面的程式碼即是Method注入的示例,最後來看下構造器注入,我們再新建一個ClothProductServiceImpl用於生產服裝
1 package service; 2 3 import javax.inject.Inject; 4 5 import annotation.*; 6 import model.Product; 7 8 @Cloth 9 public class ClothProductServiceImpl implements ProductService { 10 11 private Product product; 12 13 /** 14 * 構造器注入 15 * @param p 16 */ 17 @Inject 18 public ClothProductServiceImpl(Product p ){ 19 p.setProductName("A New Dress"); 20 p.setProductNo("SPRIT-001"); 21 product = p; 22 23 } 24 25 public Product getNewProduct() { 26 return product; 27 } 28 29 }
執行時,系統會自動給構造器ClothProductServiceImpl傳遞一個例項化的Product物件作為引數,以實現Product例項的注入。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1600/viewspace-2808616/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mongodb-java-driver基本用法MongoDBJava
- JAVA的陣列基本用法Java陣列
- JAVA CDI 學習- @Produces及@DisposesJava
- 淺談vue中provide和inject 用法VueIDE
- mongodb-java-driver的基本用法MongoDBJava
- Java反射和註解基本用法Java反射
- Java裡的Character類的基本用法Java
- Promise基本用法Promise
- Git基本用法Git
- mongoose基本用法Go
- tcpdump基本用法TCP
- GORM基本用法GoORM
- 在Java SE下測試CDI Bean和持久層 - relationJavaBean
- vue 3 學習筆記 (八)——provide 和 inject 用法及原理Vue筆記IDE
- MongoDB的基本用法MongoDB
- webpack的基本用法Web
- rematch的基本用法REM
- Promise的基本用法Promise
- jquery ajax基本用法jQuery
- scp命令基本用法
- mysqldump的基本用法MySql
- CDI元件技術(一)元件
- provide/injectIDE
- Quartz:基本用法總結quartz
- React context基本用法ReactContext
- Object.defineProperty基本用法Object
- ElasticSearch之基本用法APIElasticsearchAPI
- UIScrollView的基本用法UIView
- vim配置及基本用法
- 實戰 Java 16 值型別 Record - 2. Record 的基本用法Java型別
- 反射機制的基本用法反射
- Promise含義及基本用法Promise
- MongoDB 及 PyMongo 的基本用法MongoDB
- commander.js基本用法JS
- docker 1.2 之docker基本用法Docker
- linux中grep基本用法Linux
- redux-saga基本用法Redux
- react-redux的基本用法ReactRedux