Skip to content

Commit 2ccd2bf

Browse files
committed
op client code
1 parent 2ca025f commit 2ccd2bf

File tree

9 files changed

+179
-108
lines changed

9 files changed

+179
-108
lines changed

client/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
<groupId>com.alipay.sofa.common</groupId>
2626
<artifactId>sofa-common-tools</artifactId>
2727
</dependency>
28+
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-test</artifactId>
32+
<scope>test</scope>
33+
</dependency>
2834
</dependencies>
2935

3036
</project>

client/src/main/java/org/dromara/dynamictp/client/AdminClient.java

Lines changed: 29 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,31 @@
2020
import cn.hutool.core.lang.generator.SnowflakeGenerator;
2121
import com.alipay.remoting.Connection;
2222
import com.alipay.remoting.ConnectionEventType;
23+
import com.alipay.remoting.config.BoltClientOption;
2324
import com.alipay.remoting.config.Configs;
2425
import com.alipay.remoting.exception.RemotingException;
2526
import com.alipay.remoting.rpc.RpcClient;
2627
import com.alipay.remoting.serialization.HessianSerializer;
2728
import com.alipay.remoting.serialization.SerializerManager;
28-
import lombok.Getter;
29-
import lombok.Setter;
3029
import lombok.extern.slf4j.Slf4j;
30+
import org.apache.commons.lang3.StringUtils;
3131
import org.dromara.dynamictp.client.cluster.AdminClusterManager;
3232
import org.dromara.dynamictp.client.cluster.AdminNode;
33-
import org.dromara.dynamictp.client.processor.ClientUserProcessor;
34-
import org.dromara.dynamictp.client.processor.CloseEventProcessor;
35-
import org.dromara.dynamictp.client.processor.ConnectEventProcessor;
3633
import org.dromara.dynamictp.client.loadbalance.NodeSelector;
3734
import org.dromara.dynamictp.client.loadbalance.RandomNodeSelector;
3835
import org.dromara.dynamictp.client.loadbalance.RoundRobinNodeSelector;
3936
import org.dromara.dynamictp.client.loadbalance.WeightedRoundRobinNodeSelector;
37+
import org.dromara.dynamictp.client.processor.ClientUserProcessor;
38+
import org.dromara.dynamictp.client.processor.CloseEventProcessor;
39+
import org.dromara.dynamictp.client.processor.ConnectEventProcessor;
40+
import org.dromara.dynamictp.client.properties.AdminClientProperties;
4041
import org.dromara.dynamictp.common.entity.RpcRequest;
41-
import org.springframework.beans.factory.annotation.Value;
4242

4343
import javax.annotation.PostConstruct;
4444
import javax.annotation.PreDestroy;
4545
import java.util.Collections;
4646
import java.util.List;
47+
import java.util.Objects;
4748
import java.util.concurrent.Executors;
4849
import java.util.concurrent.ScheduledExecutorService;
4950
import java.util.concurrent.TimeUnit;
@@ -59,84 +60,47 @@
5960
@Slf4j
6061
public class AdminClient {
6162

62-
@Value("${dynamictp.adminNodes:}")
63-
private String adminNodes;
64-
65-
@Value("${dynamictp.loadBalanceStrategy:roundRobin}")
66-
private String loadBalanceStrategy;
67-
68-
@Setter
69-
@Value("${dynamictp.clientName:${spring.application.name}}")
63+
private final String adminNodes;
64+
private final String loadBalanceStrategy;
7065
private String clientName;
71-
72-
@Setter
73-
@Value("${dynamictp.serviceName:${spring.application.name}}")
74-
private String serviceName;
75-
76-
@Value("${dynamictp.adminEnabled:false}")
77-
private Boolean adminEnabled;
78-
79-
@Getter
66+
private final String serviceName;
67+
private final Boolean adminEnabled;
8068
private static final SnowflakeGenerator SNOWFLAKE_GENERATOR = new SnowflakeGenerator();
81-
8269
private final RpcClient client = new RpcClient();
83-
84-
@Getter
8570
private static final HessianSerializer SERIALIZER = new HessianSerializer();
86-
87-
/**
88-
* Use AtomicReference to ensure thread safety
89-
*/
9071
private static final AtomicReference<Connection> CONNECTION_REF = new AtomicReference<>();
91-
92-
public static Connection getConnection() {
93-
return CONNECTION_REF.get();
94-
}
95-
96-
public static void setConnection(Connection connection) {
97-
CONNECTION_REF.set(connection);
98-
}
99-
100-
/**
101-
* Cluster manager
102-
*/
10372
private AdminClusterManager clusterManager;
73+
private ScheduledExecutorService heartbeatExecutor;
10474

10575
/**
10676
* Connection state management
10777
*/
10878
private final AtomicBoolean isConnected = new AtomicBoolean(false);
10979
private final AtomicInteger retryCount = new AtomicInteger(0);
11080

111-
private ScheduledExecutorService heartbeatExecutor;
81+
public AdminClient(ClientUserProcessor clientUserProcessor, AdminClientProperties properties) {
82+
this.clientName = properties.getClientName();
83+
this.serviceName = properties.getServiceName();
84+
this.adminNodes = properties.getNodes();
85+
this.loadBalanceStrategy = properties.getLoadBalanceStrategy();
86+
this.adminEnabled = properties.isEnabled();
11287

113-
public AdminClient(ClientUserProcessor clientUserProcessor) {
114-
this(clientUserProcessor, "");
88+
initRpcClient(clientUserProcessor);
11589
}
11690

117-
public AdminClient(ClientUserProcessor clientUserProcessor, String clientName) {
118-
this(clientUserProcessor, clientName, "", "", "", false);
91+
public static Connection getConnection() {
92+
return CONNECTION_REF.get();
11993
}
12094

121-
public AdminClient(ClientUserProcessor clientUserProcessor, String clientName, String serviceName, String adminNodes, String loadBalanceStrategy, Boolean adminEnabled) {
122-
if (!clientName.isEmpty()) {
123-
this.clientName = clientName;
124-
}
125-
if (!serviceName.isEmpty()) {
126-
this.serviceName = serviceName;
127-
}
128-
if (!adminNodes.isEmpty()) {
129-
this.adminNodes = adminNodes;
130-
}
131-
if (!loadBalanceStrategy.isEmpty()) {
132-
this.loadBalanceStrategy = loadBalanceStrategy;
133-
}
134-
this.adminEnabled = adminEnabled;
95+
public static void setConnection(Connection connection) {
96+
CONNECTION_REF.set(connection);
97+
}
13598

99+
private void initRpcClient(ClientUserProcessor clientUserProcessor) {
136100
client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new ConnectEventProcessor(this));
137101
client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new CloseEventProcessor(this));
138102
client.registerUserProcessor(clientUserProcessor);
139-
client.enableReconnectSwitch();
103+
client.option(BoltClientOption.CONN_RECONNECT_SWITCH, true);
140104
client.startup();
141105
SerializerManager.addSerializer(1, SERIALIZER);
142106
System.setProperty(Configs.SERIALIZER, String.valueOf(SERIALIZER));
@@ -145,12 +109,14 @@ public AdminClient(ClientUserProcessor clientUserProcessor, String clientName, S
145109
@PostConstruct
146110
public void init() {
147111
try {
112+
if (StringUtils.isBlank(clientName)) {
113+
clientName = serviceName;
114+
}
148115
initClusterManager();
149116
createConnection();
150117
startHeartbeat();
151118
} catch (Exception e) {
152119
log.error("Failed to initialize AdminClient", e);
153-
// If initialization fails, don't start heartbeat to avoid continuous retries
154120
if (heartbeatExecutor != null) {
155121
stopHeartbeat();
156122
}

client/src/main/java/org/dromara/dynamictp/client/AdminClientConstants.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,6 @@ private AdminClientConstants() {
106106
*/
107107
public static final String THREAD_NAME_HEALTH_CHECK = "DynamicTp-AdminCluster-HealthCheck";
108108

109-
// ==================== Default Values ====================
110-
111-
/**
112-
* Default node weight for load balancing
113-
*/
114-
public static final int DEFAULT_NODE_WEIGHT = 1;
115-
116109
// ==================== Request Types ====================
117110

118111
/**

client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminAutoConfiguration.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020
import org.dromara.dynamictp.client.AdminClient;
2121
import org.dromara.dynamictp.client.processor.ClientUserProcessor;
22+
import org.dromara.dynamictp.client.properties.AdminClientProperties;
2223
import org.dromara.dynamictp.client.refresh.ConfigRefresher;
2324
import org.dromara.dynamictp.common.properties.DtpProperties;
2425
import org.dromara.dynamictp.spring.DtpBaseBeanConfiguration;
2526
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2627
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2728
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2829
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
30+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2931
import org.springframework.context.annotation.Bean;
3032
import org.springframework.context.annotation.Configuration;
3133

@@ -35,15 +37,16 @@
3537
* @author eachann
3638
*/
3739
@Configuration
40+
@EnableConfigurationProperties(AdminClientProperties.class)
3841
@ConditionalOnBean({ DtpBaseBeanConfiguration.class })
3942
@AutoConfigureAfter({ DtpBaseBeanConfiguration.class })
40-
@ConditionalOnProperty(prefix = "dynamictp", name = "adminEnabled", havingValue = "true", matchIfMissing = true)
43+
@ConditionalOnProperty(prefix = "dynamictp.admin", name = "enabled", havingValue = "true", matchIfMissing = true)
4144
public class AdminAutoConfiguration {
4245

4346
@Bean
4447
@ConditionalOnMissingBean
45-
public AdminClient adminClient(ClientUserProcessor clientUserProcessor) {
46-
return new AdminClient(clientUserProcessor);
48+
public AdminClient adminClient(ClientUserProcessor clientUserProcessor, AdminClientProperties properties) {
49+
return new AdminClient(clientUserProcessor, properties);
4750
}
4851

4952
@Bean

client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
package org.dromara.dynamictp.client.autoconfigure;
1919

2020
import lombok.extern.slf4j.Slf4j;
21-
import org.dromara.dynamictp.common.properties.DtpProperties;
22-
import org.dromara.dynamictp.core.support.binder.BinderHelper;
21+
import org.apache.commons.lang3.StringUtils;
2322
import org.dromara.dynamictp.client.AdminClient;
2423
import org.dromara.dynamictp.client.AdminClientConstants;
2524
import org.dromara.dynamictp.client.processor.ClientUserProcessor;
25+
import org.dromara.dynamictp.client.properties.AdminClientProperties;
2626
import org.springframework.boot.SpringApplication;
27+
import org.springframework.boot.context.properties.bind.Bindable;
28+
import org.springframework.boot.context.properties.bind.Binder;
2729
import org.springframework.boot.env.EnvironmentPostProcessor;
2830
import org.springframework.boot.env.OriginTrackedMapPropertySource;
2931
import org.springframework.core.Ordered;
@@ -49,21 +51,19 @@ public AdminConfigEnvironmentProcessor() {
4951

5052
@Override
5153
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
52-
// Bind configuration properties first
53-
DtpProperties dtpProperties = DtpProperties.getInstance();
54-
BinderHelper.bindDtpProperties(environment, dtpProperties);
55-
56-
// Get clientName configuration from Environment
57-
String clientName = environment.getProperty("dynamictp.clientName",
58-
Objects.requireNonNull(environment.getProperty("spring.application.name")));
59-
String serviceName = environment.getProperty("dynamictp.serviceName",
60-
Objects.requireNonNull(environment.getProperty("spring.application.name")));
61-
String adminNodes = environment.getProperty("dynamictp.adminNodes");
62-
String loadBalanceStrategy = environment.getProperty("dynamictp.loadBalanceStrategy", "roundRobin");
63-
Boolean adminEnabled = Boolean.parseBoolean(environment.getProperty("dynamictp.adminEnabled", "false"));
64-
65-
// Create AdminClient with configured clientName
66-
AdminClient adminClient = new AdminClient(new ClientUserProcessor(), clientName, serviceName, adminNodes, loadBalanceStrategy, adminEnabled);
54+
AdminClientProperties props = bindAdminClientProperties(environment);
55+
56+
// Fall back to spring.application.name when not configured
57+
String appName = environment.getProperty("spring.application.name");
58+
if (StringUtils.isBlank(props.getClientName())) {
59+
props.setClientName(Objects.requireNonNull(appName));
60+
}
61+
if (StringUtils.isBlank(props.getServiceName())) {
62+
props.setServiceName(Objects.requireNonNull(appName));
63+
}
64+
65+
// Create AdminClient with configured properties
66+
AdminClient adminClient = new AdminClient(new ClientUserProcessor(), props);
6767
adminClient.init();
6868
Object response = adminClient.requestToServer(AdminClientConstants.REQUEST_TYPE_EXECUTOR_REFRESH);
6969
if (!checkPropertyExist(environment) && response instanceof Map) {
@@ -74,6 +74,20 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp
7474
adminClient.close();
7575
}
7676

77+
private AdminClientProperties bindAdminClientProperties(ConfigurableEnvironment environment) {
78+
Binder binder = Binder.get(environment);
79+
80+
AdminClientProperties props = binder.bind("dynamictp", Bindable.of(AdminClientProperties.class))
81+
.orElseGet(AdminClientProperties::new);
82+
83+
// handle relaxed binding variations (e.g. dynamictp.load-balance-strategy)
84+
if (props.getLoadBalanceStrategy() == null || props.getLoadBalanceStrategy().trim().isEmpty()) {
85+
props.setLoadBalanceStrategy(environment.getProperty("dynamictp.loadBalanceStrategy", "roundRobin"));
86+
}
87+
88+
return props;
89+
}
90+
7791
private boolean checkPropertyExist(ConfigurableEnvironment environment) {
7892
MutablePropertySources propertySources = environment.getPropertySources();
7993
return propertySources.stream().anyMatch(p -> ADMIN_PROPERTY_SOURCE_NAME.equals(p.getName()));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You Under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.dromara.dynamictp.client.properties;
19+
20+
import lombok.Data;
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
23+
/**
24+
* Properties for DynamicTp admin client.
25+
* <p>
26+
* Binds to existing keys under {@code dynamictp.*} to keep backward compatibility.
27+
*
28+
* @author yanhom
29+
* @since 1.2.4
30+
*/
31+
@Data
32+
@ConfigurationProperties(prefix = "dynamictp.admin")
33+
public class AdminClientProperties {
34+
35+
/**
36+
* Whether enable admin feature.
37+
*/
38+
private boolean enabled = false;
39+
40+
/**
41+
* Admin server nodes, separated by comma.
42+
* Format: ip:port[:weight]
43+
*/
44+
private String nodes;
45+
46+
/**
47+
* Load balance strategy for selecting admin node.
48+
*/
49+
private String loadBalanceStrategy = "roundRobin";
50+
51+
/**
52+
* Client name, default from spring.application.name.
53+
*/
54+
private String clientName;
55+
56+
/**
57+
* Service name, default from spring.application.name.
58+
*/
59+
private String serviceName;
60+
}

0 commit comments

Comments
 (0)