You need to enable JavaScript to run this app.
导航
Java SDK
最近更新时间:2024.09.13 17:28:33首次发布时间:2023.06.09 16:02:39

1. 安装SDK

1.1 下载SDK

当前SDK版本:v2.0.18

datatester-java-sdk-2.0.18.jar
未知大小

1.2 添加jar包

  1. java版本需求:Java 8及更高版本
  2. 导入方式:将jar文件添加至项目Modules

以主流IDE(IntelliJ IDEA)为例,jar包添加示例:
图片

图片

1.3 Maven依赖导入

在成功添加jar包后,您需要通过maven管理添加必要依赖。
添加依赖方式:将以下代码添加至项目pom.xml中

注意

  1. 请务必添加所有必要依赖项。
  2. 请确保您使用的依赖版本大于或等于Tester官方默认版本。
  3. 2021年12月10日log4j暴露p0漏洞,lookup存在代码注入风险,请所有客户将maven仓库中红色依赖项更新至文档所示版本。
  4. 2022年1月,Gson 2.8.6版本暴露安全漏洞,sdk已升级为2.8.9版本的支持,请客户确保项目依赖不小于官网安全版本2.8.9。
<dependencies>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.9</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.76</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.11.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.11.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.11.4</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.0.1-jre</version>
    </dependency>
    
    <dependency>
        <groupId>com.github.zafarkhaja</groupId>
        <artifactId>java-semver</artifactId>
        <version>0.9.0</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.15.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.15.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.15.0</version>
    </dependency>
    <dependency>
        <groupId>com.lmax</groupId>
        <artifactId>disruptor</artifactId>
        <version>3.4.2</version>
    </dependency>

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.0.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>2.5.0</version>
    </dependency>
    <dependency>
        <groupId>com.googlecode.protobuf-java-format</groupId>
        <artifactId>protobuf-java-format</artifactId>
        <version>1.4</version>
    </dependency>

</dependencies>

2. 代码示例
import com.bytedance.tester.AbClient;
import com.bytedance.tester.model.User;
import com.bytedance.tester.model.common.Variable;
import com.bytedance.tester.abInfo.UserAbInfoHandler;
import com.bytedance.tester.abInfo.MemoryHandler;
import java.util.HashMap;
    
public class Example {
    public static void main(String[] args) {
        /** 初始化ABTest分流类,appKey获取方式详见接口描述
         AbClient初始化环境信息,其中:
         1. meta_host: 获取meta信息的地址,私有化用户按需修改;
         2. track_host: 事件上报地址,私有化用户按需修改;
         3.setOnpremise(true): 是否指定上述两个域名,如果指定设为true
         **/
         AbClient abClient = new AbClient.Builder("2b47a1f318d78fd71854815*********").setMetaHost("xxx").setTrackHost("xxxx").setOnpremise(true).build();
        // 开启debug模式,默认打印未命中实验的用户信息
        abClient.setDebugMode(true); 
        // 声明一个用户,decisionID用于分流,trackID用于事件上报
        // decisionID: 本地分流用户标识,不用于事件上报,请替换为客户的真实用户标识
        // trackID:  事件上报用户标识,用于事件上报,请替换为客户的真实用户标识
        // add: 添加用户属性,仅用于分流,不随埋点上报
        // build: 生成User对象
        User user = new User.UserBuilder().create("decisionID", "trackID")
                .setDeviceId(6981329701821561868L) // 可选,非必要
                .add("gender", "male")
                .add("phone", null)
                .add("is_vip", false)
                .add("version", "1.2.2")
                .add("age", 18)
                .build();
        // 进组不出组内存实现接口,若用户不配置下列代码,则默认不开启“进组不出组”功能
        // 持久化存储进组信息,请自行实现 UserAbInfoHandler 接口(推荐)
        // MemoryHandler为内存存储,仅用于测试,请勿在生产环境使用
        UserAbInfoHandler memoryHandler = MemoryHandler.getInstance(); 
        abClient.setUserAbInfoHandler(memoryHandler);
        // 推荐接口
        String defaultValue = null; // 默认版本值,当分流未命中时返回该值,注意:返回值为包装后的对象,并非defaultValue本身,依然需要使用get方法获取
        Variable variable1 = abClient.activate("variantKey", user, defaultValue);
        if(null == variable1) {
            return;
        }
        Object value1 = variable1.getValue();
        if(null == value1) {
            return;
        }
        if(value1.equals("a")){
        }
        else if(value1.equals("b")){
        }
    }
}

3. 核心类介绍

3.1 User

描述: 用户对象,用于表明分流用户的详细属性
使用方式: 调用分流接口时作为入参,使用方式如下所示

// 首先通过Builder类创建用户对象,trackId为缺省值,允许为空
User.UserBuilder userBuilder = new User.UserBuilder().create("decisionId", "trackId");
// 填充device id,用于绑定尚未生成uuid的用户(可选)
userBuilder.setDeviceId(6981329701821561868L);
// 向Builder中填充用户属性
userBuilder.add("age", 18);
userBuilder.add("name", "小明");
userBuilder.add("is_vip", true);
// 生成User对象
User user = userBuilder.build();

3.2 Variable

描述: 变体对象,用于表明分流结果的详细属性
使用方式: 分流接口的返回对象基本类,使用方式如下所示

String vid = variable.vid; // 变体的ID
String type = variable.type; // 变体值的数据类型,与Tester平台配置保持一致

// 通用方法,获取Object对象,具体数据类型需要用户自行判断
Object o = variable.getValue();
// 精确数据类型
String vStr = variable.getString(); // 非字符串类型默认返回null
int vInt = variable.getInteger(); // 非int类型默认返回0
double vDouble = variable.getDouble(); // 非double类型默认返回0.0
boolean vBoolean = variable.getBoolean(); // 非boolean类型默认返回false

3.3 UserAbInfoHandler

描述:进组不出组接口
接口内容:

public interface UserAbInfoHandler {
    /**
          * 获取进组信息
          *  @param decisionId 用户分流ID
          *  @return key:实验ID  value:进组的变体ID
          */
    HashMap<String, String> query(String decisionId);

    /**
          * 更新进组信息
          *  @param decisionId 用户分流ID
          *  @param abInfo 用户进组信息,<experimentID, versionID>
          *  @return 是否成功更新
          */
    boolean createOrUpdate(String decisionId, HashMap<String, String> abInfo);
}

使用方式:

  1. 初始化AbClient时不指定UserAbInfoHandler,则默认使用空实现,不启用“进组不出组”功能。
  2. 初始化AbClient时执行setUserAbInfoHandler,使用默认提供的内存实现MemoryHandler(使用方式见代码示例)。
  3. 继承UserAbInfoHandler接口,自行实现持久化存储;初始化AbClient时通过setUserAbInfoHandler传入。

3.4 性能参数(私有化专用)

AbClient.eventDispatcher.properties

AbClient abClient = new AbClient.Builder("appKey").setMetaHost("MetaHost").setTrackHost("TrackHost").setOnpremise(true).build();
abClient.setThreadCount(4);
abClient.setQueueSize(102400);

4. 接口说明

4.1 AbClient

接口:
new AbClient.Builder(String appKey).setMetaHost(String metaHost).setTrackHost(String trackHost).setOnpremise(boolean isOnpremise).build();
描述: 初始化ABTest分流类。
参数:

  • appKey:表明您的Tester应用。出于安全考虑,此处请使用appKey而非appID表明您的应用。
    在开始集成前,首先需要在集团中接入一个项目及应用,进行SDK集成前,您需要获取对应应用的appid、appkey等信息。
    私有化场景下您可以在「全局设置」->「系统设置」->「集团设置」-> 「项目列表」中查看项目详情,可查看其中的appid、appkey等信息,详情请参见集团设置
    图片

  • metaHost :填写获取元信息的地址,默认为saas国内线上地址,saas客户的其他合法地址可在MetaHost中查看。私有化客户需修改,通常为rangers域名。海外Saas域名:MetaHost.SG

  • trackHost :填写事件上报的地址,默认为saas国内线上地址,saas客户的其他合法地址可在TrackHost中查看。私有化客户需修改,通常为sdk事件上报域名,不清楚请咨询前场或部署同学。海外Saas域名:TrackHost.SG

  • isOnpremise(default=false):表明您的应用是否属于私有化,这关系到您使用的埋点上报是否正确

说明

1、请尽早初始化AbClient,以免影响您的分流服务和埋点上报服务。
2、每个应用有且仅有一个分流类AbClient,请确保它在所有线程中的唯一性。


Meta元信息服务默认使用火山引擎A/B平台国内线上地址,请谨慎修改。saas合法地址请参考代码中MetaHost枚举类。私有化客户需修改为部署时AB服务的挂载域名。


埋点上报服务默认使用火山引擎A/B平台国内线上地址,请谨慎修改。saas合法地址请参考代码中TrackHost枚举类。私有化客户需修改为部署时AppLog服务的挂载域名。

4.2 activate

接口: Variable activate(String variantKey, User user, Object defaultValue)
描述: 获取特定key的分流结果,并上报曝光事件
参数:
variantKey:变体的key
user:用户对象
defaultValue:变体默认值
返回值: 该函数返回命中变体对象,未命中时返回默认值对象

public class Variable {
    String vid; // 变体id
    Object val; // 变体值
    String type; // 变体值的数据类型
}

说明

1、该接口与所有含有“WithImpression”字样的接口均会自动上报曝光事件,用户可在AbClient初始化时指定trackHost,调整事件上报地址。
2、事件上报接口请务必填写User中trackID字段,否则上报失效。

4.3 getABInfo

接口: HashMap<String, Variable> getABInfo(User user)
描述: 获取实验和feature的分流结果
参数:
user:用户对象
返回值: 该函数返回命中变体的Map对象,具体格式如下所示

{
  "key1": {
    "vid": "123",
    "value": "v1",
    "type": "string"
  },
  "key2": {
    "vid": "456",
    "value": false,
    "type": "boolean" 
  },
  "key3": {
    "vid": "789",
    "value": 123.45,
    "type": "double" 
  }   
}

4.4 getExperimentVariantName

接口: String getExperimentVariantName(String experimentId, User user)
描述: 获取用户命中的实验版本名称
参数:
experimentId:指定分流的实验ID
user:用户对象
返回值: 该函数返回用户命中的实验版本名称

4.5 getExperimentConfigs

接口: HashMap<String, Variable> getExperimentConfigs(String experimentId, User user)
描述: 获取用户命中的特定实验的变体详情
参数:
experimentId:指定分流的实验ID
user:用户对象
返回值: 该函数返回命中变体的Map对象,表明用户命中某个实验的变体详情,通常仅能命中一个变体。

4.6 getAllExperimentConfigs

接口: HashMap<String, Variable> getAllExperimentConfigs(User user)
描述: 获取用户命中的所有实验的变体详情
参数:
user:用户对象
返回值: 该函数返回命中变体的Map对象,表明用户命中所有实验的变体详情,通常命中多个变体。

4.7 getFeatureConfigs

接口: HashMap<String, Variable> getFeatureConfigs(String featureId, User user)
描述: 获取用户命中的特定feature的变体详情
参数:
featureId:feature ID
user:用户对象
返回值: 该函数返回命中变体的Map对象,表明用户命中某个feature的变体详情,通常仅能命中一个变体。

4.8 getAllFeatureConfigs

接口: HashMap<String, Variable> getAllFeatureConfigs(User user)
描述: 获取用户命中的所有feature的变体详情
参数:
user:用户对象
返回值: 该函数返回命中变体的Map对象,表明用户命中所有feature的变体详情,通常命中多个变体。

4.9 getExperimentVariantNameWithImpression

同接口“getExperimentVariantName”(上报曝光事件)

4.10 getExperimentConfigsWithImpression

同接口“getExperimentConfigs”(上报曝光事件)

4.11 getFeatureConfigsWithImpression

同接口“getFeatureConfigs”(上报曝光事件)

4.12 setInterval

接口: void setInterval(int n)
描述: 设置meta元信息更新的时间间隔
参数:
n:元信息自动更新时间间隔(单位:秒)

4.13 setThreadCount

接口: void setThreadCount(int n)
描述: 设置埋点上报服务的最大线程数
参数:
n:最大线程数(默认为4)

4.14 getSuccessEvents

接口: int getSuccessEvents()
描述: 获取上报成功的事件数,用于监测事件上报回调结果
返回值: 上报成功的事件数
注意: 私有化版本不支持回调函数

4.15 getFailEvents

接口: int getFailEvents()
描述: 获取上报失败的事件数,用于监测事件上报回调结果
返回值: 上报失败的事件数

4.16 getQueueEvents

接口: int getQueueEvents()
描述: 获取线程池中剩余事件数,用于监测尚未上报的事件数量
返回值: 尚未上报的事件数

4.17 Logger

ABTest服务端SDK使用文件记录log日志。如果您希望修改日志配置,请编辑文件log4j2.xml,默认的log地址为./logs。

5. 常见问题处理

如何使用Redis实现进组不出组逻辑?

请参考集成示例,redis实现

/**
  * 实现 UserAbInfoHandler 接口,并实现接口中声明的方法
  * 进组不出组,Redis实现。
  */
public class NotOutGroupRedisImplement implements UserAbInfoHandler {
    /**
          * 存储分流结果
          *  @param userId   用户ID
          *  @param hashMap  分流结果参数和值,key=分流参数,value=对应版本的标识
          *  @return
     */
    @Override
    public boolean createOrUpdate(String userId, HashMap<String, String> hashMap) {
        long res = 0 ;
        for (Map.Entry<String, String> entry : hashMap.entrySet()) {
             res = JedisUtils.getJedis().hset(userId, entry.getKey(), entry.getValue());
        }
        return res > 0 ;
    }
    /**
          * 查询用户对应的分组
          *  @param userId
          *  @return 用户对应的分流结果  key=分流参数,value=对应版本的标识
          */
    @Override
    public HashMap<String, String> query(String userId) {
        Map<String, String> resMap = JedisUtils.getJedis().hgetAll(userId);
        return (HashMap<String, String>) resMap;
    }
}

在AB分流代码中配置进组不出组的逻辑

AbClient abClient = new AbClient.Builder(appKey).build();
NotOutGroupRedisImplement notOutGroupHandler = new NotOutGroupRedisImplement();
abClient.setUserAbInfoHandler(notOutGroupHandler);
Variable variable1 = abClient.activate("variantKey", user, defaultValue);

如果获取不到uuid,或者想做匿名用户的服务端实验,如何设置?

用户类中decisionid需要使用用户唯一标识,比如客户端设备id,ssid,trackid如果是实名就设置对应的实名用户id,如果是匿名,就为空字符串,并且需要通过setDeviceId或者setWebId方法设置设备id。
注意:saas需要使用setBdDid方法

User user = new User.UserBuilder().create("decisionID", "") // trackId有值设置对应的值,没有值设置空字符串
        .setDeviceId(6981329701821561868L) //私有部署使用此方法
        .setWebId(7018215618686981329L) //Web及小程序使用此方法
        .setBdDid("H5PPHTEHXLMEGCGROGLY2343242M2LMFIMQE4VIRW76HKYWH4Q01") //saas使用此方法
        .build();