feat: 使用okhttp替换feign.

This commit is contained in:
2024-11-06 06:53:50 +08:00
parent de4d6dcdf3
commit f8ccbf727d
14 changed files with 156 additions and 213 deletions

18
pom.xml
View File

@@ -17,7 +17,6 @@
<logback.version>1.2.12</logback.version>
<fasterxml.version>2.17.0</fasterxml.version>
<snakeyaml.version>1.30</snakeyaml.version>
<feign.core.version>13.2.1</feign.core.version>
<aliyundns.sdk.version>3.0.14</aliyundns.sdk.version>
<tencent.dnspod.sdk.version>3.1.1002</tencent.dnspod.sdk.version>
</properties>
@@ -53,23 +52,6 @@
<artifactId>tencentcloud-sdk-java-dnspod</artifactId>
<version>${tencent.dnspod.sdk.version}</version>
</dependency>
<!-- feign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>${feign.core.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>${feign.core.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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";
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -1,4 +1,4 @@
package com.serliunx.ddns.client.entity;
package com.serliunx.ddns.support.okhttp;
/**
* IP地址查询响应

View File

@@ -2,3 +2,4 @@ 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
system.http.overtime=3

View File

@@ -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);

View File

@@ -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());
}
}