客户端—dubbo接口
# 整体思路
客户端接口添加自定义的注解,注解参数有服务Id,协议,路径信息;
服务端定义了一个注解扫描类,无论是Spring还是Dubbo,它们的接口都会生成一个Bean,Dubbo是ServiceBean;得到Bean后获取到注解信息,根据协议判断是HTTP还是DUBBO,创建各自的ServiceInvoker,Invoker属性有请求路径,接口名,方法参数,超时时间等;
将得到的服务id,invoker包装成serviceDefinition,用于Nacos的服务注册;
# 客户端如何在启动时注册所有服务实例?
# 抽象注册管理器
@Slf4j
public abstract class AbstractClientRegisterManager {
@Getter
private ApiProperties apiProperties;
private RegisterCenter registerCenter;
public AbstractClientRegisterManager(ApiProperties apiProperties) {
this.apiProperties = apiProperties;
ServiceLoader<RegisterCenter> serviceLoader = ServiceLoader.load(RegisterCenter.class);
registerCenter = serviceLoader.findFirst().orElseThrow(() -> {
log.error("not found RegisterCenter impl");
return new RuntimeException("not found RegisterCenter impl");
});
registerCenter.init(apiProperties.getRegisterAddress(), apiProperties.getEnv());
}
protected void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance){
registerCenter.register(serviceDefinition,serviceInstance);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Dubbo客户端注册管理器
@Slf4j
public class Dubbo27ClientRegisterManager extends AbstractClientRegisterManager implements ApplicationListener<ApplicationEvent> {
private Set<Object> set = new HashSet<>();
public Dubbo27ClientRegisterManager(ApiProperties apiProperties) {
super(apiProperties);
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ServiceBeanExportedEvent) {
try {
ServiceBean serviceBean = ((ServiceBeanExportedEvent)applicationEvent).getServiceBean();
doRegisterDubbo(serviceBean);
} catch (Exception e) {
log.error("doRegisterDubbo error", e);
throw new RuntimeException(e);
}
}else if(applicationEvent instanceof ApplicationStartedEvent) {
log.info("dubbo api started");
}
}
private void doRegisterDubbo(ServiceBean serviceBean) {
Object bean = serviceBean.getRef();
if(set.contains(bean)){
return;
}
/*构造服务定义*/
ServiceDefinition serviceDefinition = ApiAnnotationScanner.getInstance().scanner(bean, serviceBean);
if (serviceDefinition == null) {
return;
}
serviceDefinition.setEnvType(getApiProperties().getEnv());
/*构造服务实例*/
ServiceInstance serviceInstance = new ServiceInstance();
String localIp = NetUtils.getLocalIp();
int port = serviceBean.getProtocol().getPort();
String serviceInstanceId = localIp + COLON_SEPARATOR + port;
String uniqueId = serviceDefinition.getUniqueId();
String version = serviceDefinition.getVersion();
serviceInstance.setServiceInstanceId(serviceInstanceId);
serviceInstance.setUniqueId(uniqueId);
serviceInstance.setIp(localIp);
serviceInstance.setPort(port);
serviceInstance.setRegisterTime(TimeUtil.currentTimeMillis());
serviceInstance.setVersion(version);
serviceInstance.setWeight(DEFAULT_WEIGHT);
/*注册*/
register(serviceDefinition, serviceInstance);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 客户端自动装配
@Configuration
@EnableConfigurationProperties(ApiProperties.class)/*容器启动就加载配置*/
@ConditionalOnProperty(prefix = "api", name = {"registerAddress"})
public class ApiClientAutoConfiguration {
@Autowired
private ApiProperties apiProperties;
@Bean
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean(SpringMVCClientRegisterManager.class)/*没有这个Bean才创建*/
public SpringMVCClientRegisterManager springMVCClientRegisterManager() {
return new SpringMVCClientRegisterManager(apiProperties);
}
@Bean
@ConditionalOnClass({ServiceBean.class})
@ConditionalOnMissingBean(Dubbo27ClientRegisterManager.class)
public Dubbo27ClientRegisterManager dubbo27ClientRegisterManager() {
return new Dubbo27ClientRegisterManager(apiProperties);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 服务调用接口模型描述
# ServiceInvoker
public interface ServiceInvoker {
/**
* 获取真正的服务调用的全路径
*/
String getInvokerPath();
void setInvokerPath(String invokerPath);
/**
* 获取该服务调用(方法)的超时时间
*/
int getTimeout();
void setTimeout(int timeout);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# AbstractServiceInvoker
public class AbstractServiceInvoker implements ServiceInvoker {
protected String invokerPath;
protected int timeout = 5000;
@Override
public String getInvokerPath() {
return invokerPath;
}
@Override
public void setInvokerPath(String invokerPath) {
this.invokerPath = invokerPath;
}
@Override
public int getTimeout() {
return timeout;
}
@Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# DubboServiceInvoker
@Data
public class DubboServiceInvoker extends AbstractServiceInvoker{
private String registerAddress;
private String interfaceClass;
private String methodName;
private String[] parameterTypes;
private String version;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 客户端注解
# ApiService
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiService {
String serviceId();
String version() default "1.0.0";
ApiProtocol protocol();
String patternPath();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# ApiInvoker
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiInvoker {
String path();
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# Dubbo服务管理
# ApiProperties
@Data
@ConfigurationProperties(prefix = "api")
public class ApiProperties {
private String registerAddress;
private String env = "dev";
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# AbstractClientRegisterManager
@Slf4j
public abstract class AbstractClientRegisterManager {
@Getter
private ApiProperties apiProperties;
private RegisterCenter registerCenter;
public AbstractClientRegisterManager(ApiProperties apiProperties) {
this.apiProperties = apiProperties;
ServiceLoader<RegisterCenter> serviceLoader = ServiceLoader.load(RegisterCenter.class);
registerCenter = serviceLoader.findFirst().orElseThrow(() -> {
log.error("not found RegisterCenter impl");
return new RuntimeException("not found RegisterCenter impl");
});
registerCenter.init(apiProperties.getRegisterAddress(), apiProperties.getEnv());
}
protected void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance){
registerCenter.register(serviceDefinition,serviceInstance);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Dubbo27ClientRegisterManager
@Slf4j
public class Dubbo27ClientRegisterManager extends AbstractClientRegisterManager implements ApplicationListener<ApplicationEvent> {
private Set<Object> set = new HashSet<>();
public Dubbo27ClientRegisterManager(ApiProperties apiProperties) {
super(apiProperties);
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ServiceBeanExportedEvent) {
try {
ServiceBean serviceBean = ((ServiceBeanExportedEvent)applicationEvent).getServiceBean();
doRegisterDubbo(serviceBean);
} catch (Exception e) {
log.error("doRegisterDubbo error", e);
throw new RuntimeException(e);
}
}else if(applicationEvent instanceof ApplicationStartedEvent) {
log.info("dubbo api started");
}
}
private void doRegisterDubbo(ServiceBean serviceBean) {
Object bean = serviceBean.getRef();
if(set.contains(bean)){
return;
}
/*构造服务定义*/
ServiceDefinition serviceDefinition = ApiAnnotationScanner.getInstance().scanner(bean, serviceBean);
if (serviceDefinition == null) {
return;
}
serviceDefinition.setEnvType(getApiProperties().getEnv());
/*构造服务实例*/
ServiceInstance serviceInstance = new ServiceInstance();
String localIp = NetUtils.getLocalIp();
int port = serviceBean.getProtocol().getPort();
String serviceInstanceId = localIp + COLON_SEPARATOR + port;
String uniqueId = serviceDefinition.getUniqueId();
String version = serviceDefinition.getVersion();
serviceInstance.setServiceInstanceId(serviceInstanceId);
serviceInstance.setUniqueId(uniqueId);
serviceInstance.setIp(localIp);
serviceInstance.setPort(port);
serviceInstance.setRegisterTime(TimeUtil.currentTimeMillis());
serviceInstance.setVersion(version);
serviceInstance.setWeight(DEFAULT_WEIGHT);
/*注册*/
register(serviceDefinition, serviceInstance);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 根据ServiceBean组装ServiceDefinition
@NoArgsConstructor
public class ApiAnnotationScanner {
private static class SingletonHolder{
static final ApiAnnotationScanner INSTANCE = new ApiAnnotationScanner();
}
public static ApiAnnotationScanner getInstance(){
return SingletonHolder.INSTANCE;
}
/*传入bean,返回ServiceDefinition*/
public ServiceDefinition scanner(Object bean, Object... args){
Class<?> aClass = bean.getClass();
if(!aClass.isAnnotationPresent(ApiService.class)){
return null;
}
ApiService apiService = aClass.getAnnotation(ApiService.class);
String serviceId = apiService.serviceId();
ApiProtocol protocol = apiService.protocol();
String patternPath = apiService.patternPath();
String version = apiService.version();
ServiceDefinition serviceDefinition = new ServiceDefinition();
Map<String, ServiceInvoker> invokerMap = new HashMap<>();
Method[] methods = aClass.getMethods();
if(methods!=null && methods.length>0){
for(Method method : methods){
ApiInvoker apiInvoker = method.getAnnotation(ApiInvoker.class);
if(apiInvoker == null){
continue;
}
String path = apiInvoker.path();
switch (protocol){
case HTTP:
HttpServiceInvoker httpServiceInvoker = createHttpServiceInvoker(path);
invokerMap.put(path,httpServiceInvoker);
break;
case DUBBO:
ServiceBean<?> serviceBean = (ServiceBean<?>) args[0];
DubboServiceInvoker dubboServiceInvoker = createDubboServiceInvoker(path, serviceBean, method);
String dubboVersion = dubboServiceInvoker.getVersion();
if (!StringUtils.isBlank(dubboVersion)) {
version = dubboVersion;
}
invokerMap.put(path, dubboServiceInvoker);
break;
default:
break;
}
}
serviceDefinition.setUniqueId(serviceId + BasicConst.COLON_SEPARATOR + version);
serviceDefinition.setServiceId(serviceId);
serviceDefinition.setVersion(version);
serviceDefinition.setProtocol(protocol.getCode());
serviceDefinition.setPatternPath(patternPath);
serviceDefinition.setEnable(true);
serviceDefinition.setInvokerMap(invokerMap);
return serviceDefinition;
}
return null;
}
private HttpServiceInvoker createHttpServiceInvoker(String path){
HttpServiceInvoker httpServiceInvoker = new HttpServiceInvoker();
httpServiceInvoker.setInvokerPath(path);
return httpServiceInvoker;
}
private DubboServiceInvoker createDubboServiceInvoker(String path, ServiceBean<?> serviceBean, Method method){
DubboServiceInvoker dubboServiceInvoker = new DubboServiceInvoker();
dubboServiceInvoker.setInvokerPath(path);
String methodName = method.getName();
String registerAddress = serviceBean.getRegistry().getAddress();
String interfaceClass = serviceBean.getInterface();
dubboServiceInvoker.setRegisterAddress(registerAddress);
dubboServiceInvoker.setMethodName(methodName);
dubboServiceInvoker.setInterfaceClass(interfaceClass);
String[] parameterTypes = new String[method.getParameterCount()];
Class<?>[] classes = method.getParameterTypes();
for (int i = 0; i < classes.length; i++) {
parameterTypes[i] = classes[i].getName();
}
dubboServiceInvoker.setParameterTypes(parameterTypes);
Integer seriveTimeout = serviceBean.getTimeout();
if (seriveTimeout == null || seriveTimeout.intValue() == 0) {
ProviderConfig providerConfig = serviceBean.getProvider();
if (providerConfig != null) {
Integer providerTimeout = providerConfig.getTimeout();
if (providerTimeout == null || providerTimeout.intValue() == 0) {
seriveTimeout = DubboConstants.DUBBO_TIMEOUT;
} else {
seriveTimeout = providerTimeout;
}
}
}
dubboServiceInvoker.setTimeout(seriveTimeout);
String dubboVersion = serviceBean.getVersion();
dubboServiceInvoker.setVersion(dubboVersion);
return dubboServiceInvoker;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 客户端自动配置
@Configuration
@EnableConfigurationProperties(ApiProperties.class)/*容器启动就加载配置*/
@ConditionalOnProperty(prefix = "api", name = {"registerAddress"})
public class ApiClientAutoConfiguration {
@Autowired
private ApiProperties apiProperties;
@Bean
@ConditionalOnClass({ServiceBean.class})
@ConditionalOnMissingBean(Dubbo27ClientRegisterManager.class)
public Dubbo27ClientRegisterManager dubbo27ClientRegisterManager() {
return new Dubbo27ClientRegisterManager(apiProperties);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17