首页 > IT职业 > IT生活 > 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 http://www.apache.org/licenses/LICENSE-2.0 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 29http://jboss.org/jbossas 3031 37 3832 36Apache License, Version 2.0 33repo 34http://www.apache.org/licenses/LICENSE-2.0.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 <!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html --> 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" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 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中部署后,浏览http://localhost:8080/cdi-web-sample/faces/index.xhtml 或http://localhost:8080/cdi-web-sample/index.jsf

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博客 ” ,链接:https://blog.itpub.net/1600/viewspace-2808616/ ,如需转载,请注明出处,否则将追究法律责任。