Spring Cloud学习教程之DiscoveryClient的深入探究

2025-05-29 0 97

前言

当我们使用@discoveryclient注解的时候,会不会有如下疑问:它为什么会进行注册服务的操作,它不是应该用作服务发现的吗?下面我们就来深入的探究一下其源码。

一、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类就实现了该接口

Spring Cloud学习教程之DiscoveryClient的深入探究

下面我们来简单演示一下案例,创建类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运行 会得到如下结果:

Spring Cloud学习教程之DiscoveryClient的深入探究

另外在这里的getphase方法,这个是定义阶段值(可以理解为优先级,值越小对应的lifecycle越先执行)

二、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 ,我们来看一下结构图:

Spring Cloud学习教程之DiscoveryClient的深入探究

我们可以得知这个类实现了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接口的实现用作服务发现

三、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的默认装配。

当我们启动成功后可以发现,控制台已经输出对应的服务名称与地址:

Spring Cloud学习教程之DiscoveryClient的深入探究

我们再次通过gradle打包生成jar文件并运行:

1
java -jar member-server-0.0.1-snapshot.jar --server.port=8800

我们可以看到redis里已经缓存的有服务注册的值了:

Spring Cloud学习教程之DiscoveryClient的深入探究

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对快网idc的支持。

原文链接:https://www.cnblogs.com/niechen/p/8893759.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Spring Cloud学习教程之DiscoveryClient的深入探究 https://www.kuaiidc.com/111647.html

相关文章

发表评论
暂无评论