Kong提供了Http的管理API祠墅,可以實(shí)現(xiàn)對(duì)Kong的管理难审。我們利用Kong的Amin API沙绝,實(shí)現(xiàn)一套JAVA的管理API慢蜓。這里以添加一個(gè)Service和Route為示例:
使用retrofit2實(shí)現(xiàn)
添加Maven依賴(lài)
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>${retrofit.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
</dependency>
實(shí)現(xiàn)kong客戶(hù)端的架子
添加Kong客戶(hù)端
@Data
public class KongClient {
private ServiceService serviceService;
private RouteService routeService;
public KongClient(String adminUrl) {
if (adminUrl == null || adminUrl.isEmpty()) {
throw new IllegalArgumentException("The adminUrl cannot be null or empty!");
}
RetrofitServiceCreator retrofitServiceCreatorForAdminUrl = new RetrofitServiceCreator(adminUrl);
{
serviceService = retrofitServiceCreatorForAdminUrl.create(ServiceService.class,RetrofitServiceService.class);
routeService = retrofitServiceCreatorForAdminUrl.create(RouteService.class,RetrofitRouteService.class);
}
}
}
添加Retrofit處理類(lèi)
public class RetrofitServiceCreator {
private Retrofit retrofit;
// -------------------------------------------------------------------
public RetrofitServiceCreator(String baseUrl) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(initOkHttpClient(baseUrl.toLowerCase().startsWith("https"))) // support https
.addConverterFactory(CustomGsonConverterFactory.create()) // replace GsonConverterFactory
}
// -------------------------------------------------------------------
@SuppressWarnings("unchecked")
public <T> T create(Class<T> serviceInterface, Class<?> retrofitServiceInterface) {
Object proxied = retrofit.create(retrofitServiceInterface);
return (T) Proxy.newProxyInstance(
RetrofitServiceCreator.class.getClassLoader(),
new Class[] { serviceInterface },
new RetrofitBodyExtractorInvocationHandler(proxied));
}
public <T> T createRetrofitService(Class<T> retrofitServiceInterface) {
return retrofit.create(retrofitServiceInterface);
}
// -------------------------------------------------------------------
private OkHttpClient initOkHttpClient(boolean supportHttps) {
if(supportHttps) {
HttpsUtil.SSLParams sslParams = HttpsUtil.getSslSocketFactory(null, null, null);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.build();
return okHttpClient;
}
return new OkHttpClient.Builder().build();
}
}
添加動(dòng)態(tài)代理處理類(lèi)
@Slf4j
public class RetrofitBodyExtractorInvocationHandler implements InvocationHandler {
private Object proxied;
public RetrofitBodyExtractorInvocationHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
Method method1 = proxied.getClass().getMethod(methodName, parameterTypes);
Call call = (Call) method1.invoke(proxied, args);
Response response = call.execute();
log.debug("Http Request: " + response.raw().request());
log.debug("Http Response: " + response.raw().toString());
if(!response.isSuccessful()) {
throw new KongClientException(response.errorBody() != null ? response.errorBody().string() : String.valueOf(response.code()));
}
return response.body();
}
}
添加自定義JSON轉(zhuǎn)換工廠
class CustomGsonConverterFactory extends Converter.Factory {
private final Gson gson;
private CustomGsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
public static CustomGsonConverterFactory create() {
return create(new Gson());
}
public static CustomGsonConverterFactory create(Gson gson) {
return new CustomGsonConverterFactory(gson);
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonRequestBodyConverter<>(gson, adapter);
}
}
實(shí)現(xiàn)Service的Java Admin API
添加Service實(shí)體
@Data @Builder
public class Service {
private String id;
private String name;
private String protocol;
private String host;
private Integer port;
private String path;
private String url;
private Integer retries;
@SerializedName("connect_timeout")
private Long connectTimeout;
@SerializedName("read_timeout")
private Long readTimeout;
@SerializedName("write_timeout")
private Long writeTimeout;
@SerializedName("created_at")
private Long createdAt;
@SerializedName("updated_at")
private Long updatedAt;
}
添加Service接口亚再,這里只要?jiǎng)h除和新增
public interface ServiceService {
Service addService(Service service);
void deleteService(String nameOrId);
}
添加Retrofit的處理接口
public interface RetrofitServiceService {
@POST("services/")
Call<Service> addService(@Body Service request);
@DELETE("services/{nameOrId}")
Call<Void> deleteService(@Path("nameOrId") String nameOrId);
}
實(shí)現(xiàn)Route的Java Admin API
添加Route實(shí)體
@Data @Builder
public class Route {
private String id;
private List<String> protocols;
private List<String> methods;
private List<String> hosts;
private List<String> paths;
@SerializedName("strip_path")
private Boolean stripPath;
@SerializedName("preserve_host")
private Boolean preserveHost;
private Service service;
@SerializedName("created_at")
private Long createdAt;
@SerializedName("updated_at")
private Long updatedAt;
}
添加Route接口,這里只要?jiǎng)h除和新增
public interface RouteService {
Route addRoute(Route route);
void DeleteRoute(String id);
}
添加Retrofit的處理接口
public interface RetrofitRouteService {
@POST("routes/")
Call<Route> addRoute(@Body Route route);
@DELETE("routes/{id}")
Call<Void> DeleteRoute(@Path("id") String id);
}
單元測(cè)試一下
新建一個(gè)名字為example-service
晨抡,地址為http://mockbin.org
的Service氛悬。并為Service添加host為example.com
的Route路由。
public class ServiceRouteTest extends BaseTest {
public static final String EXAMPLE_SERVICE = "example-service";
@Test
public void createServiceAndRouteTest(){
// 刪除Route和Service
CommonList<Route> commonList = kongClient.getRouteService().listRoutesByService(EXAMPLE_SERVICE);
List<Route> routeList = commonList.getData();
if(null!=routeList && routeList.size()>0 ){
for (Route route : routeList) {
kongClient.getRouteService().DeleteRoute(route.getId());
}
}
kongClient.getServiceService().deleteService(EXAMPLE_SERVICE);
// 新建Service和Route
Service service = Service.builder().url("http://mockbin.org").name(EXAMPLE_SERVICE).build();
Service response4service = kongClient.getServiceService().addService(service);
printJson(response4service);
List<String> hostList = new ArrayList<>();
hostList.add("example.com");
Route route = Route.builder().hosts(hostList).service(Service.builder().id(response4service.getId()).build()).build();
Route response4route = kongClient.getRouteService().addRoute(route);
printJson(response4route);
}
}
最后耘柱,檢查下效果
使用GET
方法如捅,訪問(wèn)地址http://192.168.56.112:8000
,并添加在頭部添加host[]=example.com
调煎,結(jié)果如下:
使用Postman測(cè)試Kong
寫(xiě)在最后
- 利用架子可以自定義其他Kong的JAVA客戶(hù)端镜遣。
- 很多時(shí)候,我們的API地址是通過(guò)程序掃描出來(lái)的士袄,或者管理系統(tǒng)進(jìn)行配置的悲关。這個(gè)時(shí)候,我們就可以利用Kong的JAVA客戶(hù)端快速的實(shí)現(xiàn)Kong的接口管理娄柳,輪訓(xùn)等寓辱。
- 應(yīng)用降級(jí)赤拒,流控秫筏,金絲雀诱鞠,灰度等等,都可以通過(guò)Kong的JAVA客戶(hù)端輕松實(shí)現(xiàn)跳昼。