feat: 使用okhttp替换feign.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package com.serliunx.ddns;
|
||||
|
||||
import com.serliunx.ddns.config.Configuration;
|
||||
import com.serliunx.ddns.config.PropertiesConfiguration;
|
||||
import com.serliunx.ddns.constant.SystemConstants;
|
||||
import com.serliunx.ddns.core.context.FileInstanceContext;
|
||||
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
|
||||
import com.serliunx.ddns.support.SystemInitializer;
|
||||
import com.serliunx.ddns.support.okhttp.HttpClient;
|
||||
|
||||
/**
|
||||
* 启动类
|
||||
@@ -14,17 +17,65 @@ import com.serliunx.ddns.support.SystemInitializer;
|
||||
*/
|
||||
public final class ManagerLite {
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
*/
|
||||
private static Configuration configuration;
|
||||
/**
|
||||
* 实例容器
|
||||
*/
|
||||
private static MultipleSourceInstanceContext instanceContext;
|
||||
/**
|
||||
* 系统初始化器
|
||||
*/
|
||||
private static SystemInitializer systemInitializer;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 容器初始化
|
||||
init();
|
||||
|
||||
// 配置初始化
|
||||
initConfiguration();
|
||||
|
||||
// 相关工具初始化
|
||||
initTools();
|
||||
|
||||
// 初始化实例容器
|
||||
initContext();
|
||||
|
||||
// 系统初始化
|
||||
initSystem();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
SystemInitializer systemInitializer = SystemInitializer
|
||||
/**
|
||||
* 初始化实例容器
|
||||
*/
|
||||
private static void initContext() {
|
||||
instanceContext = new FileInstanceContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置初始化
|
||||
*/
|
||||
private static void initConfiguration() {
|
||||
configuration = new PropertiesConfiguration(SystemConstants.USER_SETTINGS_PROPERTIES_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 相关工具初始化
|
||||
*/
|
||||
private static void initTools() {
|
||||
// http 工具类初始化
|
||||
HttpClient.init(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统初始化
|
||||
*/
|
||||
private static void initSystem() {
|
||||
systemInitializer = SystemInitializer
|
||||
.configurer()
|
||||
.clearCache(false)
|
||||
.configuration(new PropertiesConfiguration(SystemConstants.USER_SETTINGS_PROPERTIES_PATH))
|
||||
.instanceContext(new FileInstanceContext())
|
||||
.configuration(configuration)
|
||||
.instanceContext(instanceContext)
|
||||
.done();
|
||||
systemInitializer.refresh();
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.serliunx.ddns.client;
|
||||
|
||||
import com.serliunx.ddns.client.entity.IPAddressResponse;
|
||||
import com.serliunx.ddns.support.feign.JacksonDecoder;
|
||||
import com.serliunx.ddns.support.feign.JacksonEncoder;
|
||||
import feign.Feign;
|
||||
import feign.Logger;
|
||||
import feign.RequestLine;
|
||||
import feign.Retryer;
|
||||
import feign.slf4j.Slf4jLogger;
|
||||
|
||||
/**
|
||||
* 本机外网IP地址获取
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/15
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public interface IPAddressClient {
|
||||
|
||||
static final String url = "http://ip-api.com";
|
||||
|
||||
static final IPAddressClient instance = getInstance();
|
||||
|
||||
/**
|
||||
* 获取本机外网IP地址
|
||||
* @return IPAddressResponse
|
||||
*/
|
||||
@RequestLine("GET /json")
|
||||
IPAddressResponse getIPAddress();
|
||||
|
||||
static IPAddressClient getInstance() {
|
||||
return Feign.builder()
|
||||
.logger(new Slf4jLogger())
|
||||
.logLevel(Logger.Level.BASIC)
|
||||
.retryer(Retryer.NEVER_RETRY)
|
||||
.encoder(JacksonEncoder.getInstance())
|
||||
.decoder(JacksonDecoder.getInstance())
|
||||
.target(IPAddressClient.class, url);
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,9 @@ public final class ConfigurationKeys {
|
||||
* 阿里云解析线路
|
||||
*/
|
||||
public static final String KEY_ALIYUN_ENDPOINT = "instance.aliyun.endpoint.url";
|
||||
|
||||
/**
|
||||
* http请求超时时间(秒)
|
||||
*/
|
||||
public static final String KEY_HTTP_OVERTIME = "system.http.overtime";
|
||||
}
|
||||
|
||||
@@ -18,12 +18,14 @@ public interface InstanceFactory extends Priority, Comparable<InstanceFactory>,
|
||||
/**
|
||||
* 添加实例
|
||||
* <li> 此方法默认为不覆盖的方式添加, 即如果存在则添加失败, 没有任何返回值和异常.
|
||||
*
|
||||
* @param instance 实例信息
|
||||
*/
|
||||
void addInstance(Instance instance);
|
||||
|
||||
/**
|
||||
* 根据实例名称获取实例
|
||||
*
|
||||
* @param instanceName 实例名称
|
||||
* @return 实例信息, 如果不存在则会抛出异常
|
||||
*/
|
||||
@@ -31,7 +33,7 @@ public interface InstanceFactory extends Priority, Comparable<InstanceFactory>,
|
||||
|
||||
@Override
|
||||
default int compareTo(InstanceFactory o) {
|
||||
if(getPriority() < o.getPriority()){
|
||||
if (getPriority() < o.getPriority()) {
|
||||
return 1;
|
||||
} else if (this.getPriority() > o.getPriority()) {
|
||||
return -1;
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.serliunx.ddns.config.Configuration;
|
||||
*/
|
||||
public final class ConfigurationContextHolder {
|
||||
|
||||
private static final ThreadLocal<Configuration> CONFIGURATION_HOLDER = new ThreadLocal<>();
|
||||
private static volatile Configuration configuration;
|
||||
|
||||
private ConfigurationContextHolder() {throw new UnsupportedOperationException();}
|
||||
|
||||
@@ -22,7 +22,7 @@ public final class ConfigurationContextHolder {
|
||||
* @return 配置信息
|
||||
*/
|
||||
public static Configuration getConfiguration() {
|
||||
return CONFIGURATION_HOLDER.get();
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,10 @@ public final class ConfigurationContextHolder {
|
||||
*
|
||||
* @param configuration 配置信息
|
||||
*/
|
||||
public static void setConfiguration(Configuration configuration) {
|
||||
CONFIGURATION_HOLDER.set(configuration);
|
||||
public static synchronized void setConfiguration(Configuration configuration) {
|
||||
if (ConfigurationContextHolder.configuration != null) {
|
||||
return;
|
||||
}
|
||||
ConfigurationContextHolder.configuration = configuration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import com.serliunx.ddns.core.Clearable;
|
||||
import com.serliunx.ddns.core.Refreshable;
|
||||
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
|
||||
import com.serliunx.ddns.core.instance.Instance;
|
||||
import com.serliunx.ddns.client.IPAddressClient;
|
||||
import com.serliunx.ddns.client.entity.IPAddressResponse;
|
||||
import com.serliunx.ddns.support.okhttp.IPAddressResponse;
|
||||
import com.serliunx.ddns.support.okhttp.HttpClient;
|
||||
import com.serliunx.ddns.thread.TaskThreadFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -169,7 +169,7 @@ public final class SystemInitializer implements Refreshable, Clearable {
|
||||
scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
|
||||
InstanceContextHolder.setAdditional("ip-update");
|
||||
log.info("正在尝试获取本机最新的IP地址.");
|
||||
IPAddressResponse response = IPAddressClient.instance.getIPAddress();
|
||||
IPAddressResponse response = HttpClient.getIPAddress();
|
||||
String ip;
|
||||
if(response != null
|
||||
&& (ip = response.getQuery()) != null) {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package com.serliunx.ddns.support.feign;
|
||||
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
import feign.codec.Decoder;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* feign解码器
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/15
|
||||
*/
|
||||
public class JacksonDecoder implements Decoder {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
private static final JacksonDecoder decoder = new JacksonDecoder();
|
||||
|
||||
private JacksonDecoder() {
|
||||
this(Collections.emptyList());
|
||||
}
|
||||
|
||||
private JacksonDecoder(Iterable<Module> modules) {
|
||||
this(new ObjectMapper()
|
||||
//设置下划线自动转化为驼峰命名
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
.registerModules(modules));
|
||||
}
|
||||
|
||||
private JacksonDecoder(ObjectMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public static Decoder getInstance() {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Response response, Type type) throws FeignException, IOException {
|
||||
if (response.status() == 404 || response.status() == 204)
|
||||
return Util.emptyValueOf(type);
|
||||
if (response.body() == null)
|
||||
return null;
|
||||
Reader reader = response.body().asReader(response.charset());
|
||||
if (!reader.markSupported()) {
|
||||
reader = new BufferedReader(reader, 1);
|
||||
}
|
||||
//处理响应体字符流
|
||||
try{
|
||||
reader.mark(1);
|
||||
if (reader.read() == -1) {
|
||||
return null;
|
||||
}
|
||||
reader.reset();
|
||||
return mapper.readValue(reader, mapper.constructType(type));
|
||||
} catch (RuntimeJsonMappingException e) {
|
||||
if (e.getCause() != null && e.getCause() instanceof IOException) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
throw e;
|
||||
}finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.serliunx.ddns.support.feign;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import feign.RequestTemplate;
|
||||
import feign.Util;
|
||||
import feign.codec.EncodeException;
|
||||
import feign.codec.Encoder;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Feign兼容Jackson(反序列化返回值)
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/15
|
||||
*/
|
||||
public class JacksonEncoder implements Encoder {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
private static final JacksonEncoder encoder = new JacksonEncoder();
|
||||
|
||||
private JacksonEncoder() {
|
||||
this(Collections.emptyList());
|
||||
}
|
||||
|
||||
private JacksonEncoder(Iterable<Module> modules) {
|
||||
this(new ObjectMapper()
|
||||
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
.configure(SerializationFeature.INDENT_OUTPUT, true)
|
||||
.registerModules(modules));
|
||||
}
|
||||
|
||||
private JacksonEncoder(ObjectMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public static Encoder getInstance() {
|
||||
return encoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Object object, Type bodyType, RequestTemplate template) {
|
||||
try {
|
||||
JavaType javaType = mapper.getTypeFactory().constructType(bodyType);
|
||||
template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new EncodeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.serliunx.ddns.support.okhttp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.serliunx.ddns.config.Configuration;
|
||||
import com.serliunx.ddns.config.ConfigurationKeys;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Http 客户端工具类
|
||||
* <li> 使用okhttp实现
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.2
|
||||
* @since 2024/11/6
|
||||
*/
|
||||
public final class HttpClient {
|
||||
|
||||
private static OkHttpClient CLIENT = null;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
|
||||
private static final ObjectMapper JSON_MAPPER = new JsonMapper();
|
||||
|
||||
private HttpClient() {throw new UnsupportedOperationException();}
|
||||
|
||||
/**
|
||||
* 获取本机的ip地址
|
||||
*
|
||||
* @return 响应结果
|
||||
*/
|
||||
public static IPAddressResponse getIPAddress() {
|
||||
Request request = new Request.Builder()
|
||||
.url("http://ip-api.com/json")
|
||||
.get()
|
||||
.build();
|
||||
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
if (!response.isSuccessful() || response.body() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String body = response.body().string();
|
||||
if (body.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON_MAPPER.readValue(body, IPAddressResponse.class);
|
||||
} catch (Exception e) {
|
||||
log.error("ip地址获取异常:", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param configuration 配置信息
|
||||
*/
|
||||
public static void init(Configuration configuration) {
|
||||
Integer overtime = configuration.getInteger(ConfigurationKeys.KEY_HTTP_OVERTIME, 3);
|
||||
|
||||
CLIENT = new OkHttpClient.Builder()
|
||||
.connectTimeout(overtime, TimeUnit.SECONDS)
|
||||
.readTimeout(overtime, TimeUnit.SECONDS)
|
||||
.writeTimeout(overtime, TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.serliunx.ddns.client.entity;
|
||||
package com.serliunx.ddns.support.okhttp;
|
||||
|
||||
/**
|
||||
* IP地址查询响应
|
||||
@@ -1,4 +1,5 @@
|
||||
system.cfg.log.onstart=true
|
||||
system.pool.core.size=4
|
||||
system.task.refresh.interval.ip=300
|
||||
instance.aliyun.endpoint.url=alidns.cn-hangzhou.aliyuncs.com
|
||||
instance.aliyun.endpoint.url=alidns.cn-hangzhou.aliyuncs.com
|
||||
system.http.overtime=3
|
||||
@@ -22,9 +22,9 @@ public class ContextTest {
|
||||
public void testGenericContext() {
|
||||
GenericInstanceContext genericInstanceContext = new GenericInstanceContext(true);
|
||||
|
||||
// genericInstanceContext.addListableInstanceFactory(new XmlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
// genericInstanceContext.addListableInstanceFactory(new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
// genericInstanceContext.addListableInstanceFactory(new JsonFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
genericInstanceContext.addListableInstanceFactory(new XmlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
genericInstanceContext.addListableInstanceFactory(new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
genericInstanceContext.addListableInstanceFactory(new JsonFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
|
||||
|
||||
genericInstanceContext.refresh();
|
||||
genericInstanceContext.getInstances().forEach(System.out::println);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.serliunx.ddns.test.support;
|
||||
|
||||
import com.serliunx.ddns.client.IPAddressClient;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@@ -11,7 +10,6 @@ public class ClientTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
IPAddressClient client = IPAddressClient.instance;
|
||||
System.out.println(client.getIPAddress().getQuery());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user