- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring Cloud学习教程之DiscoveryClient的深入探究由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
当我们使用@discoveryclient注解的时候,会不会有如下疑问:它为什么会进行注册服务的操作,它不是应该用作服务发现的吗?下面我们就来深入的探究一下其源码.
1、springframework的lifecycle接口 。
要搞明白这个问题我们需要了解一下这个重要的接口:
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
|
/*
* copyright 2002-2015 the original author or authors.
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*/
package org.springframework.context;
/**
* a common interface defining methods for start/stop lifecycle control.
* the typical use case for this is to control asynchronous processing.
* <b>note: this interface does not imply specific auto-startup semantics.
* consider implementing {@link smartlifecycle} for that purpose.</b>
*
* <p>can be implemented by both components (typically a spring bean defined in a
* spring context) and containers (typically a spring {@link applicationcontext}
* itself). containers will propagate start/stop signals to all components that
* apply within each container, e.g. for a stop/restart scenario at runtime.
*
* <p>can be used for direct invocations or for management operations via jmx.
* in the latter case, the {@link org.springframework.jmx.export.mbeanexporter}
* will typically be defined with an
* {@link org.springframework.jmx.export.assembler.interfacebasedmbeaninfoassembler},
* restricting the visibility of activity-controlled components to the lifecycle
* interface.
*
* <p>note that the lifecycle interface is only supported on <b>top-level singleton
* beans</b>. on any other component, the lifecycle interface will remain undetected
* and hence ignored. also, note that the extended {@link smartlifecycle} interface
* provides integration with the application context's startup and shutdown phases.
*
* @author juergen hoeller
* @since 2.0
* @see smartlifecycle
* @see configurableapplicationcontext
* @see org.springframework.jms.listener.abstractmessagelistenercontainer
* @see org.springframework.scheduling.quartz.schedulerfactorybean
*/
public interface lifecycle {
/**
* start this component.
* <p>should not throw an exception if the component is already running.
* <p>in the case of a container, this will propagate the start signal to all
* components that apply.
* @see smartlifecycle#isautostartup()
*/
void start();
/**
* stop this component, typically in a synchronous fashion, such that the component is
* fully stopped upon return of this method. consider implementing {@link smartlifecycle}
* and its {@code stop(runnable)} variant when asynchronous stop behavior is necessary.
* <p>note that this stop notification is not guaranteed to come before destruction: on
* regular shutdown, {@code lifecycle} beans will first receive a stop notification before
* the general destruction callbacks are being propagated; however, on hot refresh during a
* context's lifetime or on aborted refresh attempts, only destroy methods will be called.
* <p>should not throw an exception if the component isn't started yet.
* <p>in the case of a container, this will propagate the stop signal to all components
* that apply.
* @see smartlifecycle#stop(runnable)
* @see org.springframework.beans.factory.disposablebean#destroy()
*/
void stop();
/**
* check whether this component is currently running.
* <p>in the case of a container, this will return {@code true} only if <i>all</i>
* components that apply are currently running.
* @return whether the component is currently running
*/
boolean
isrunning();
}
|
该接口定义启动/停止生命周期控制方法,当spring ioc容器启动或停止时将发送一个启动或者停止的信号通知到各个组件,因此我们可以在对应的方法里做我们想要的事情。我们可以通过类图发现我们常用的classpathxmlapplicationcontext类就实现了该接口 。
下面我们来简单演示一下案例,创建类mylifecycle:
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
|
package
org.hzgj.spring.study.context;
import
org.springframework.context.smartlifecycle;
public
class
mylifecycle
implements
smartlifecycle {
@override
public
void
start() {
system.out.println(
"mylifecycle start ...."
);
}
@override
public
void
stop() {
system.out.println(
"mylifecycle stop ....."
);
}
@override
public
boolean
isrunning() {
return
false
;
}
@override
public
boolean
isautostartup() {
return
true
;
}
@override
public
void
stop(runnable callback) {
}
@override
public
int
getphase() {
system.out.println(
"phase"
);
return
10
;
}
}
|
在这里我们继承smartlifecycle该接口继承了lifecycle, isrunning方法用于检测当前的组件是否处在运行状态,注意只有当isrunning返回值为false才可以运行 。
我们把mylifecycle配置到spring配置文件里,通过classpathxmlapplicationcontext运行 会得到如下结果:
另外在这里的getphase方法,这个是定义阶段值(可以理解为优先级,值越小对应的lifecycle越先执行) 。
2、discoveryclient源码探究 。
@enablediscoveyclient 。
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
|
/*
* copyright 2013-2015 the original author or authors.
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*/
package org.springframework.cloud.client.discovery;
import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.inherited;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
import org.springframework.context.annotation.import;
/**
* annotation to enable a discoveryclient implementation.
* @author spencer gibb
*/
@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@inherited
@import(enablediscoveryclientimportselector.class)
public @interface enablediscoveryclient {
/**
* if true, the serviceregistry will automatically register the local server.
*/
boolean
autoregister()
default
true
;
}
|
请注意 @import(enablediscoveryclientimportselector.class) 我们可以参考一下这个类:
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
|
/*
* copyright 2013-2015 the original author or authors.
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*/
package org.springframework.cloud.client.discovery;
import org.springframework.boot.bind.relaxedpropertyresolver;
import org.springframework.cloud.commons.util.springfactoryimportselector;
import org.springframework.core.ordered;
import org.springframework.core.annotation.annotationattributes;
import org.springframework.core.annotation.order;
import org.springframework.core.env.configurableenvironment;
import org.springframework.core.env.environment;
import org.springframework.core.env.mappropertysource;
import org.springframework.core.type.annotationmetadata;
import java.util.arraylist;
import java.util.arrays;
import java.util.linkedhashmap;
import java.util.list;
/**
* @author spencer gibb
*/
@order
(ordered.lowest_precedence -
100
)
public
class
enablediscoveryclientimportselector
extends
springfactoryimportselector<enablediscoveryclient> {
@override
public
string[] selectimports(annotationmetadata metadata) {
string[] imports =
super
.selectimports(metadata);
annotationattributes attributes = annotationattributes.frommap(
metadata.getannotationattributes(getannotationclass().getname(),
true
));
boolean
autoregister = attributes.getboolean(
"autoregister"
);
if
(autoregister) {
list<string> importslist =
new
arraylist<>(arrays.aslist(imports));
importslist.add(
"org.springframework.cloud.client.serviceregistry.autoserviceregistrationconfiguration"
);
imports = importslist.toarray(
new
string[
0
]);
}
else
{
environment env = getenvironment();
if
(configurableenvironment.
class
.isinstance(env)) {
configurableenvironment configenv = (configurableenvironment)env;
linkedhashmap<string, object> map =
new
linkedhashmap<>();
map.put(
"spring.cloud.service-registry.auto-registration.enabled"
,
false
);
mappropertysource propertysource =
new
mappropertysource(
"springclouddiscoveryclient"
, map);
configenv.getpropertysources().addlast(propertysource);
}
}
return
imports;
}
@override
protected
boolean
isenabled() {
return
new
relaxedpropertyresolver(getenvironment()).getproperty(
"spring.cloud.discovery.enabled"
,
boolean
.
class
,
boolean
.
true
);
}
@override
protected
boolean
hasdefaultfactory() {
return
true
;
}
}
|
这个类重写的方法来自于接口 importselector,我们可以根据 if(autoregister)下的代码追踪到类:org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration ,我们来看一下结构图:
我们可以得知这个类实现了lifecycle接口,那么我们看一看start方法,此方法在它的父类abstractdiscoverylifecycle里:
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
/*
* copyright 2013-2015 the original author or authors.
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*/
package org.springframework.cloud.client.discovery;
import java.util.concurrent.atomic.atomicboolean;
import java.util.concurrent.atomic.atomicinteger;
import javax.annotation.predestroy;
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
import org.springframework.beans.beansexception;
import org.springframework.boot.context.embedded.embeddedservletcontainerinitializedevent;
import org.springframework.cloud.client.discovery.event.instanceregisteredevent;
import org.springframework.cloud.client.serviceregistry.serviceregistry;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.context.applicationlistener;
import org.springframework.core.env.environment;
/**
* lifecycle methods that may be useful and common to various discoveryclient implementations.
*
* @deprecated use {@link org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration} instead. this class will be removed in the next release train.
*
* @author spencer gibb
*/
@deprecated
public abstract class abstractdiscoverylifecycle implements discoverylifecycle,
applicationcontextaware, applicationlistener<embeddedservletcontainerinitializedevent> {
private static final log logger = logfactory.getlog(abstractdiscoverylifecycle.class);
private boolean autostartup = true;
private atomicboolean running = new atomicboolean(false);
private int order = 0;
private applicationcontext context;
private environment environment;
private atomicinteger port = new atomicinteger(0);
protected applicationcontext getcontext() {
return context;
}
@override
public void setapplicationcontext(applicationcontext applicationcontext)
throws beansexception {
this.context = applicationcontext;
this.environment = this.context.getenvironment();
}
@deprecated
protected environment getenvironment() {
return environment;
}
@deprecated
protected atomicinteger getport() {
return port;
}
@override
public boolean isautostartup() {
return this.autostartup;
}
@override
public void stop(runnable callback) {
try {
stop();
} catch (exception e) {
logger.error("a problem occurred attempting to stop discovery lifecycle", e);
}
callback.run();
}
@override
public void start() {
if (!isenabled()) {
if (logger.isdebugenabled()) {
logger.debug("discovery lifecycle disabled. not starting");
}
return;
}
// only set the port if the nonsecureport is 0 and this.port != 0
if (this.port.get() != 0 && getconfiguredport() == 0) {
setconfiguredport(this.port.get());
}
// only initialize if nonsecureport is greater than 0 and it isn't already running
// because of containerportinitializer below
if (!this.running.get() && getconfiguredport() > 0) {
register();
if (shouldregistermanagement()) {
registermanagement();
}
this.context.publishevent(new instanceregisteredevent<>(this,
getconfiguration()));
this.running.compareandset(false, true);
}
}
@deprecated
protected abstract int getconfiguredport();
@deprecated
protected abstract void setconfiguredport(int port);
/**
* @return if the management service should be registered with the {@link serviceregistry}
*/
protected boolean shouldregistermanagement() {
return getmanagementport() != null && managementserverportutils.isdifferent(this.context);
}
/**
* @return the object used to configure the registration
*/
@deprecated
protected abstract object getconfiguration();
/**
* register the local service with the discoveryclient
*/
protected abstract void register();
/**
* register the local management service with the discoveryclient
*/
protected void registermanagement() {
}
/**
* de-register the local service with the discoveryclient
*/
protected abstract void deregister();
/**
* de-register the local management service with the discoveryclient
*/
protected void deregistermanagement() {
}
/**
* @return true, if the {@link discoverylifecycle} is enabled
*/
protected abstract boolean isenabled();
/**
* @return the serviceid of the management service
*/
@deprecated
protected string getmanagementserviceid() {
// todo: configurable management suffix
return this.context.getid() + ":management";
}
/**
* @return the service name of the management service
*/
@deprecated
protected string getmanagementservicename() {
// todo: configurable management suffix
return getappname() + ":management";
}
/**
* @return the management server port
*/
@deprecated
protected integer getmanagementport() {
return managementserverportutils.getport(this.context);
}
/**
* @return the app name, currently the spring.application.name property
*/
@deprecated
protected
string getappname() {
return
this
.environment.getproperty(
"spring.application.name"
,
"application"
);
}
@override
public
void
stop() {
if
(
this
.running.compareandset(
true
,
false
) && isenabled()) {
deregister();
if
(shouldregistermanagement()) {
deregistermanagement();
}
}
}
@predestroy
public
void
destroy() {
stop();
}
@override
public
boolean
isrunning() {
return
this
.running.get();
}
protected
atomicboolean getrunning() {
return
running;
}
@override
public
int
getorder() {
return
this
.order;
}
@override
public
int
getphase() {
return
0
;
}
@override
@deprecated
public
void
onapplicationevent(embeddedservletcontainerinitializedevent event) {
// todo: take ssl into account
// don't register the management port as the port
if
(!
"management"
.equals(event.getapplicationcontext().getnamespace())) {
this
.port.compareandset(
0
, event.getembeddedservletcontainer().getport());
this
.start();
}
}
}
|
注意在start方法里有一段这个代码:
1
2
3
4
5
6
7
8
9
|
if
(!
this
.running.get() && getconfiguredport() >
0
) {
register();
if
(shouldregistermanagement()) {
registermanagement();
}
this
.context.publishevent(
new
instanceregisteredevent<>(
this
,
getconfiguration()));
this
.running.compareandset(
false
,
true
);
}
|
请注意register() 这个方法是本类里的抽象方法。那么我们回过头看一下abstractautoserviceregistration类里的代码,我这里只贴出关键部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//.....
protected
abstractautoserviceregistration(serviceregistry<r> serviceregistry, autoserviceregistrationproperties properties) {
this
.serviceregistry = serviceregistry;
this
.properties = properties;
}
//......
/**
* register the local service with the {@link serviceregistry}
*/
@override
protected
void
register() {
this
.serviceregistry.register(getregistration());
}
|
我们可以发现在构造函数里传了一个serviceregistry类型,这个接口是springcloud给我们提供用于服务注册的接口。在这里eurekaserviceregistry就是实现了此接口:
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
|
/*
* copyright 2013-2016 the original author or authors.
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*
*/
package org.springframework.cloud.netflix.eureka.serviceregistry;
import java.util.hashmap;
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
import org.springframework.cloud.client.serviceregistry.serviceregistry;
import com.netflix.appinfo.instanceinfo;
/**
* @author spencer gibb
*/
public
class
eurekaserviceregistry
implements
serviceregistry<eurekaregistration> {
private
static
final
log log = logfactory.getlog(eurekaserviceregistry.
class
);
@override
public
void
register(eurekaregistration reg) {
maybeinitializeclient(reg);
if
(log.isinfoenabled()) {
log.info(
"registering application "
+ reg.getinstanceconfig().getappname()
+
" with eureka with status "
+ reg.getinstanceconfig().getinitialstatus());
}
reg.getapplicationinfomanager()
.setinstancestatus(reg.getinstanceconfig().getinitialstatus());
if
(reg.gethealthcheckhandler() !=
null
) {
reg.geteurekaclient().registerhealthcheck(reg.gethealthcheckhandler());
}
}
private
void
maybeinitializeclient(eurekaregistration reg) {
// force initialization of possibly scoped proxies
reg.getapplicationinfomanager().getinfo();
reg.geteurekaclient().getapplications();
}
@override
public
void
deregister(eurekaregistration reg) {
if
(reg.getapplicationinfomanager().getinfo() !=
null
) {
if
(log.isinfoenabled()) {
log.info(
"unregistering application "
+ reg.getinstanceconfig().getappname()
+
" with eureka with status down"
);
}
reg.getapplicationinfomanager().setinstancestatus(instanceinfo.instancestatus.down);
//shutdown of eureka client should happen with eurekaregistration.close()
//auto registration will create a bean which will be properly disposed
//manual registrations will need to call close()
}
}
@override
public
void
setstatus(eurekaregistration registration, string status) {
instanceinfo info = registration.getapplicationinfomanager().getinfo();
//todo: howto deal with delete properly
if
(
"cancel_override"
.equalsignorecase(status)) {
registration.geteurekaclient().canceloverridestatus(info);
return
;
}
//todo: howto deal with status types across discovery systems
instanceinfo.instancestatus newstatus = instanceinfo.instancestatus.toenum(status);
registration.geteurekaclient().setstatus(newstatus, info);
}
@override
public
object getstatus(eurekaregistration registration) {
hashmap<string, object> status =
new
hashmap<>();
instanceinfo info = registration.getapplicationinfomanager().getinfo();
status.put(
"status"
, info.getstatus().tostring());
status.put(
"overriddenstatus"
, info.getoverriddenstatus().tostring());
return
status;
}
public
void
close() {
}
}
|
那么至此我们可以总结如下几点:
1、使用@discoveryclient注册服务是利用了lifecycle机制,在容器启动时会执行serviceregistry的register()方法.
2、使用@discoveryclient要比@enableeurekaclient与@enableeurekaserver更灵活,因为它屏蔽了对服务注册的实现,我们甚至可以自定义注册中心.
3、这里面还会自动去寻找discoveryclient接口的实现用作服务发现 。
3、discoveryclient实战之redis注册中心 。
下面我们实现一个基于redis为注册中心的需求,来理解一下discoveryclient。顺便理解一下springcloud重要的接口:serviceregistry,serviceinstance,再此之前我们先添加对redis的支持:
1
|
compile group:
'org.springframework.boot'
, name:
'spring-boot-starter-data-redis'
|
1、实现registration接口 。
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
109
110
111
112
|
package
com.hzgj.lyrk.member;
import
org.springframework.beans.factory.annotation.value;
import
org.springframework.cloud.client.serviceregistry.registration;
import
org.springframework.stereotype.component;
import
java.net.inetaddress;
import
java.net.networkinterface;
import
java.net.uri;
import
java.util.enumeration;
import
java.util.map;
@component
public
class
redisregistration
implements
registration {
@value
(
"${server.port}"
)
private
integer port;
@value
(
"${spring.application.name}"
)
private
string applicationname;
private
string host;
public
void
sethost(string host) {
this
.host = host;
}
public
void
setport(integer port) {
this
.port = port;
}
public
void
setapplicationname(string applicationname) {
this
.applicationname = applicationname;
}
@override
public
string getserviceid() {
return
applicationname +
":"
+ gethost() +
":"
+ getport();
}
@override
public
string gethost() {
try
{
if
(host ==
null
)
return
getlocalhostlanaddress().gethostaddress();
else
return
host;
}
catch
(exception e) {
e.printstacktrace();
}
return
null
;
}
@override
public
int
getport() {
return
port;
}
@override
public
boolean
issecure() {
return
false
;
}
@override
public
uri geturi() {
return
null
;
}
@override
public
map<string, string> getmetadata() {
return
null
;
}
public
string getservicename() {
return
this
.applicationname;
}
public
inetaddress getlocalhostlanaddress()
throws
exception {
try
{
inetaddress candidateaddress =
null
;
// 遍历所有的网络接口
for
(enumeration ifaces = networkinterface.getnetworkinterfaces(); ifaces.hasmoreelements(); ) {
networkinterface iface = (networkinterface) ifaces.nextelement();
// 在所有的接口下再遍历ip
for
(enumeration inetaddrs = iface.getinetaddresses(); inetaddrs.hasmoreelements(); ) {
inetaddress inetaddr = (inetaddress) inetaddrs.nextelement();
if
(!inetaddr.isloopbackaddress()) {
// 排除loopback类型地址
if
(inetaddr.issitelocaladdress()) {
// 如果是site-local地址,就是它了
return
inetaddr;
}
else
if
(candidateaddress ==
null
) {
// site-local类型的地址未被发现,先记录候选地址
candidateaddress = inetaddr;
}
}
}
}
if
(candidateaddress !=
null
) {
return
candidateaddress;
}
// 如果没有发现 non-loopback地址.只能用最次选的方案
inetaddress jdksuppliedaddress = inetaddress.getlocalhost();
return
jdksuppliedaddress;
}
catch
(exception e) {
e.printstacktrace();
}
return
null
;
}
}
|
该接口继承了serviceintance,那么此接口最主要作用就是定义了一个服务实例的规范,比如说它的serviceid是什么,端口号是什么等 。
2、实现serviceregistry的接口 。
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
|
package
com.hzgj.lyrk.member;
import
org.springframework.beans.factory.annotation.autowired;
import
org.springframework.cloud.client.serviceregistry.serviceregistry;
import
org.springframework.data.redis.core.stringredistemplate;
public
class
redisserviceregistry
implements
serviceregistry<redisregistration> {
@autowired
private
stringredistemplate redistemplate;
@override
public
void
register(redisregistration registration) {
string serviceid = registration.getserviceid();
redistemplate.opsforlist().leftpush(serviceid, registration.gethost() +
":"
+ registration.getport());
}
@override
public
void
deregister(redisregistration registration) {
redistemplate.opsforlist().remove(registration.getserviceid(),
1
, registration.gethost() +
":"
+ registration.getport());
}
@override
public
void
close() {
//redistemplate.d
system.out.println(
"closed ..."
);
}
@override
public
void
setstatus(redisregistration registration, string status) {
}
@override
public
<t> t getstatus(redisregistration registration) {
return
null
;
}
}
|
该接口主要作用是定义如何进行服务注册 ,服务注销,设置与获取服务状态等操作 。
3、继承 abstractautoserviceregistration抽象类 。
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
|
package
com.hzgj.lyrk.member;
import
org.springframework.beans.factory.annotation.autowired;
import
org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration;
import
org.springframework.cloud.client.serviceregistry.autoserviceregistrationproperties;
import
org.springframework.cloud.client.serviceregistry.serviceregistry;
public
class
redisautoserviceregistration
extends
abstractautoserviceregistration<redisregistration> {
@autowired
private
redisregistration redisregistration;
protected
redisautoserviceregistration(serviceregistry<redisregistration> serviceregistry, autoserviceregistrationproperties properties) {
super
(serviceregistry, properties);
// serviceregistry.register(getregistration());
}
@override
protected
int
getconfiguredport() {
return
redisregistration.getport();
}
@override
protected
void
setconfiguredport(
int
port) {
}
@override
protected
object getconfiguration() {
return
null
;
}
@override
protected
boolean
isenabled() {
return
true
;
}
@override
protected
redisregistration getregistration() {
return
redisregistration;
}
@override
protected
redisregistration getmanagementregistration() {
return
null
;
}
}
|
4、定义discoveryclient的实现类redisdiscoveryclient 。
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
|
package
com.hzgj.lyrk.member;
import
org.apache.commons.lang.stringutils;
import
org.springframework.beans.factory.annotation.autowired;
import
org.springframework.cloud.client.serviceinstance;
import
org.springframework.cloud.client.discovery.discoveryclient;
import
org.springframework.data.redis.core.stringredistemplate;
import
java.util.arraylist;
import
java.util.list;
import
java.util.function.function;
import
java.util.stream.collectors;
public
class
redisdiscoveryclient
implements
discoveryclient {
@autowired
private
stringredistemplate redistemplate;
@override
public
string description() {
return
"redis注册中心的服务发现"
;
}
@override
public
serviceinstance getlocalserviceinstance() {
return
null
;
}
@override
public
list<serviceinstance> getinstances(string serviceid) {
return
redistemplate.opsforlist().range(serviceid,
0
, -
1
).
parallelstream().map((function<string, serviceinstance>) s -> {
redisregistration redisregistration =
new
redisregistration();
redisregistration.setapplicationname(serviceid);
string hostname = stringutils.split(s,
":"
)[
0
];
string port = stringutils.split(s,
":"
)[
1
];
redisregistration.sethost(hostname);
redisregistration.setport(integer.parseint(port));
//redisregistration
return
redisregistration;
}).collect(collectors.tolist());
}
@override
public
list<string> getservices() {
list<string> list =
new
arraylist<>();
list.addall(redistemplate.keys(
"*"
));
return
list;
}
}
|
该类主要是针对于redis注册中心的服务发现 。
5、定义自动装配的类用以创建对应的bean 。
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
|
package
com.hzgj.lyrk.member;
import
org.springframework.boot.autoconfigure.condition.conditionalonproperty;
import
org.springframework.boot.context.properties.enableconfigurationproperties;
import
org.springframework.cloud.client.serviceregistry.autoserviceregistrationproperties;
import
org.springframework.context.annotation.bean;
import
org.springframework.context.annotation.configuration;
import
org.springframework.context.annotation.primary;
@configuration
@enableconfigurationproperties
(redisconfig.
class
)
@conditionalonproperty
(value =
"spring.redis.registry.enabled"
, matchifmissing =
true
)
public
class
redisregistryautoconfiguration {
@bean
redisserviceregistry redisserviceregistry(redisconfig redisconfig) {
system.out.println(redisconfig.gethost());
return
new
redisserviceregistry();
}
@bean
redisautoserviceregistration redisautoserviceregistration(redisserviceregistry redisserviceregistry) {
return
new
redisautoserviceregistration(redisserviceregistry,
new
autoserviceregistrationproperties());
}
@bean
@primary
redisdiscoveryclient redisdiscoveryclient() {
return
new
redisdiscoveryclient();
}
}
|
6、定义启动类 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package
com.hzgj.lyrk.member;
import
org.springframework.boot.springapplication;
import
org.springframework.boot.autoconfigure.springbootapplication;
import
org.springframework.cloud.client.discovery.discoveryclient;
import
org.springframework.cloud.client.discovery.enablediscoveryclient;
import
org.springframework.cloud.client.discovery.composite.compositediscoveryclientautoconfiguration;
import
org.springframework.cloud.client.discovery.simple.simplediscoveryclientautoconfiguration;
import
org.springframework.context.configurableapplicationcontext;
@enablediscoveryclient
@springbootapplication
(exclude = {simplediscoveryclientautoconfiguration.
class
, compositediscoveryclientautoconfiguration.
class
})
public
class
memberapplication {
public
static
void
main(string[] args) {
configurableapplicationcontext applicationcontext = springapplication.run(memberapplication.
class
, args);
discoveryclient discoveryclient = applicationcontext.getbean(discoveryclient.
class
);
discoveryclient.getservices().foreach(action -> {
system.out.println(action);
});
}
}
|
这里在springbootapplication注解里排除discoveryclient的默认装配.
当我们启动成功后可以发现,控制台已经输出对应的服务名称与地址:
我们再次通过gradle打包生成jar文件并运行
1
|
java -jar member-server-
0.0
.
1
-snapshot.jar --server.port=
8800
|
我们可以看到redis里已经缓存的有服务注册的值了:
总结 。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://www.cnblogs.com/niechen/p/8893759.html 。
最后此篇关于Spring Cloud学习教程之DiscoveryClient的深入探究的文章就讲到这里了,如果你想了解更多关于Spring Cloud学习教程之DiscoveryClient的深入探究的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在使用 Spring 靴 1.3.3 org.springframework.boot spring-boot-starter-parent 1.3.3.RELEASE
我创建了 带有复制功能的 Eureka 服务器 现在尝试启动客户端。当我尝试启动 spring-microservices-eureka-client 时,我收到以下错误。使用 Spring Boot
当我通过浏览器调用该方法本身时,它正在工作,并且我得到了预期的 JSON。因此该方法正在运行并且所请求的服务已注册。 @RequestMapping("/getArticle/{article
我已经设置了 Intershop Commerce Management 7.8 并且一切正常,除了我在错误日志文件中不断出现错误。 Eureka 正在运行,我可以使用 http://localhos
我正在使用 Spring OAuth2RestTemplate 来访问 REST 服务。我需要更改我的代码使用 Eureka 进行服务发现。所有通信都必须是 HTTPS 并且我在客户端有一个 trus
尝试访问发现客户端以访问其他端点并跟随, http://docs.identityserver.io/en/aspnetcore1/endpoints/discovery.html 在 .Net 7.
pom.xml 出现问题。除了 spring-cloud-starter-netflix-eureka-client 之外,所有依赖项都得到了很好的解决。我做错了什么?请帮忙。 Maven 版本 4.
如标题所示:控制台应用程序在执行以下行时崩溃 disco = await DiscoveryClient.GetAsync("http://localhost:5000"); 没有异常抛出,即使我把它
我正在尝试构建自己的 DiscoveryClient ,它将使用 Docker Swarm 作为服务源。我已经让它与 Spring Cloud Gateway 和 Spring Cloud Loadb
2017-03-16 16:09:08.821 INFO 9104 --- [ main] com.hello.EurekaClientApplication :
我正在尝试将使用 spring-cloud-starter-netflix-zuul 的网关迁移到 Spring Cloud Gateway,但我遇到了请求路由问题。 我浏览了以下有关为 Discov
我从Spring blog借用了下面的代码在这里。 @SpringBootApplication @EnableEurekaClient @EnableFeignClients public clas
DiscoveryClient 还需要什么?我正在尝试使用 DiscoveryClient 将已注册的服务提取到 Eureka 。独立程序运行良好,但以下代码片段将与在 JBoss 上运行的 Web
我们的 Web 应用程序托管在一个 SSL 终止集群后面。我调用 DiscoveryClient.GetAsync var discoveryClient = DiscoveryClient.GetA
我是一名优秀的程序员,十分优秀!