前面几节学习到的CDI内容,基本上都是hard-code,以硬编码的方式在代码里指定注入类型,这并非依赖注入的本意,依赖注入的优势之一在于“解耦”,这一节我们将学习如何利用配置来动态注入的类型及属性初始化。
一、@Alternative/@Default/@Any
当一个服务接口(也称契约)有多个实现时,可以在代码里指定一个缺省的实现类型(即:标注成@Default或@Any),其它实现类标注成@Alternative,以后如果需要动态切换实现类,只要在webapp/WEB-INF/beans.xml中配置即可。
1.1 新建二个示例接口
1 packagecontract;2
3 public interfaceConnection {4
5 String connect();6
7 }
Connection
该接口模拟db连接,里面有一个connect方法,用来连接db.
1 packagecontract;2
3 public interfaceDriveService {4
5 String drive();6
7 }
DriveService
该接口模拟游戏应用中,有些人物具有驾驶技能。
1.2 提供接口实现
假设Connection有二个实现,一个用来连接到Oracle Database,另一个用来连接Microsoft Sql Server
1 packagecontract.impl;2
3 importjavax.enterprise.inject.Default;4
5 importcontract.Connection;6
7 @Default8 public class OracleConnection implementsConnection {9
10 @Override11 publicString connect() {12
13 return "Oracle Database is connecting...";14 }15
16 }
OracleConnection
1 packagecontract.impl;2
3 importjavax.enterprise.inject.Alternative;4
5 importcontract.Connection;6
7 @Alternative8 public class SqlServerConnection implementsConnection {9
10 @Override11 publicString connect() {12
13 return "Microsoft SqlServer is connecting...";14 }15
16 }
SqlServerConnection
注:OracleConnection上应用了注解@Default,表示这是接口Connection的默认实现类(@Default实质上是系统的默认注解,其实也可以省略,系统会自动默认为@Default);SqlServerConnection上应用了注解@Alternative,表示它是候选项,俗称:备胎:),所有非@Default的实现类,都必须标识@Alternative,否则注入时,会提示“不明确的类型”
再来看DriveService的实现,我们提供三种实现:驾驶汽车、摩托车、拖拉机
1 packagecontract.impl;2
3 importcontract.DriveService;4
5 public class CarDriveImpl implementsDriveService {6
7 @Override8 publicString drive() {9 String msg = "Drive a car...";10 System.out.println(msg);11 returnmsg;12 }13
14 }
CarDriveImpl
1 packagecontract.impl;2
3 importjavax.enterprise.inject.Alternative;4
5 importcontract.DriveService;6
7 @Alternative8 public class MotorcycleDriveImpl implementsDriveService {9
10 @Override11 publicString drive() {12 String msg = "Drive a motocycle...";13 System.out.println(msg);14 returnmsg;15 }16
17 }
MotorcycleDriveImpl
1 packagecontract.impl;2
3 importjavax.enterprise.inject.Alternative;4
5 importcontract.DriveService;6
7 @Alternative8 public class TractorDriveImpl implementsDriveService {9
10 @Override11 publicString drive() {12 String msg = "Drive a tractor...";13 System.out.println(msg);14 returnmsg;15 }16
17 }
TractorDriveImpl
注:MotocycleDriveImpl、TractorDriveImpl这二个类使用了@Alternative,即它们俩是候选,剩下的CarDriveImpl上未使用任何注解,即默认的@Default
1.3 编写Controller类
1 packagecontroller;2
3 importjavax.inject.Inject;4 importjavax.inject.Named;5
6 importcontract.Connection;7
8 @Named("Conn")9 public classConnectionController {10
11 @Inject12 privateConnection conn;13
14 publicConnection getConn() {15 returnconn;16 }17
18 }
ConnectionController
1 packagecontroller;2
3 import javax.enterprise.inject.*;4 importjavax.inject.Inject;5 importjavax.inject.Named;6
7 importcontract.DriveService;8
9 @Named("Drive")10 public classDriveController {11
12 @Inject13 privateDriveService driveService;14
15 publicDriveService getDriveService() {16 returndriveService;17 }18
19 @Inject20 @Any21 private InstanceanySerInstance;22
23 publicDriveService getAnySerInstance() {24 returnanySerInstance.get();25 }26
27 }
DriveController
注:DriveController中anySerInstance成员上使用了@Any,从本例最终使用的效果上看,它跟@Default一样,只不过细节要留意一下,需要使用Instance接口,这点跟@Default有点不同。
1.4 UI层
1
2
3 xmlns:h="http://java.sun.com/jsf/html"
4 xmlns:f="http://java.sun.com/jsf/core"
5 xmlns:ui="http://java.sun.com/jsf/facelets">
6
7
8
CDI - Alternative/Default/Any9
10
11 #{Drive.driveService.drive()}12
13
#{Drive.anySerInstance.drive()}14
15
#{Conn.conn.connect()}16
17