一、整体项目结构
1、项目结构
首先我们创建一个父工程,然后其的POM文件是:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<properties>
<spring-cloud-version>Finchley.RELEASE</spring-cloud-version>
</properties>
<groupId>com.fev</groupId>
<artifactId>spring-cloud-demo</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<dependencies>
<!--解决TypeNotPresentException 如果是jdk9 需要添加-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
我们当前使用的spring-cloud
的版本是Finchley.RELEASE
。
二、eureka注册中心使用
1、项目创建
我们再添加一个子模块,用于eureka注册中心
2、项目结构
可以看到我们的eureka注册中心是很简单的。
3、项目内容
1)、POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.fev</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>euerka-server1</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
这里引用了spring-cloud-starter-netflix-eureka-server
,用于注入eureka
客户端内容
2)、application文件
server:
port: 7001
spring:
application:
name: eureka-server1 #应用名称
eureka:
instance:
hostname: localhost #本服务实例名称
client:
#需不需要将自己注册到注册中心 false表示不用,因为其本身就是server
register-with-eureka: false
#需不需要从注册中心获取其他的服务,由于是服务端,其是维护服务的,所以其也为false
fetch-registry: false
service-url:
# 表示注册中心地址,向这个地址来注册实例
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3)、Application类
@SpringBootApplication
@EnableEurekaServer
public class EuerkaServerApplication1 {
public static void main(String[] args) {
SpringApplication.run(EuerkaServerApplication1.class,args);
}
}
这个也很简单,只需要加@EnableEurekaServer
表明这个是eureka
服务端
4、启动服务
我们启动后,就可以输入http://localhost:7001
就可以看到eureka
服务端的界面了,目前没有向它注册的实例,所以是Noinstances available
。
三、eureka客户端
下面我们就编写客户端来向服务端注册
1、项目创建
我们再在父工程创建一个客户端子模块
2、项目结构
3、项目内容
1)、POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.fev</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-client1</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
这里是引用了一个spring-cloud-starter-netflix-eureka-client
来注入eureka
客户端相关的内容
2)、application文件
server:
port: 7005
eureka:
instance:
hostname: localhost
instance-id: eureka-client7005
client:
# 从注册中心获取注册信息
fetch-registry: true
# 将本服务注册到注册中心
register-with-eureka: true
service-url:
# defaultZone: http://localhost:7001/eureka,http://localhost:7001/eureka
defaultZone: http://localhost:7001/eureka
spring:
application:
name: eureka-client
3)、Application类
@SpringBootApplication
@EnableEurekaClient
public class EurekaClient1 {
public static void main(String[] args) {
SpringApplication.run(EurekaClient1.class,args);
}
}
这里和前面注册中心类似,只是这里加的是客户端注@EnableEureClient
。
4、启动服务
我们现在启动客户端服务,就可以在7001
注册中心看到这个注册的实例了。
5、拓展说明
上面我们只是简单的说明了注册中心与客户端的关系,不过其实你要使用这种微服务模型,简单是有三个服务。
注册中心:这个用来给所有的客户端注册的。
生产者与消费者:这是表示其他的两个服务,其对于注册中心来说都是客户端,都注册到注册中心。然后这两个客户端之间通过注册中心来相互调用,例如一个服务(消费者)需要去另一个服务(生产者)调用接口获取信息,比如一个客户服务需要调用订单服务获取这个客户的所有订单信息,这个关系也是相对的,也可以是要获取一个订单的具体客户信息。
6、eureka额外设置
1)、eureka客户端配置
server:
port: 7005
eureka:
instance:
hostname: localhost
# 主机ID
instance-id: eureka-client7005
# 展示主机IP
prefer-ip-address: true
client:
# 从注册中心获取注册信息
fetch-registry: true
# 将本服务注册到注册中心
register-with-eureka: true
service-url:
defaultZone: http://localhost:7001/eureka
spring:
application:
name: eureka-client
这里与前面相比,多了几个属性。一个是instance-id
,这个表示的是展示的主机ID,然后prefer-ip-address
表示的是需要展示的IP(不然展示的就是hostname
主机名称),我们以这个配置启动客户端,再看eureka注册中心页面:
可以看到我们现在多例一个实例eureka-client7005
,就是我们设置的instance-id
。这里有一个问题,我们只是重启了服务,但为什么原来的实例名称LAPTOP-QR83QEC0:eureka-client:7005
还是存在?这里我们下面再讲。
2)、eureka注册中心的自我保护
这个自我保护就是:我们知道一般在客户端与注册中心之间是通过定时发送心跳包来确定两服务都还是开启的,但可能存在暂时性的网络波动,我们一般不会例如因为一次或短期的几次就判定这个客户端已经挂了,直接将这个注册的服务就删除了,而是注册中心开启自我保护模式,即使发送心跳没有回复我们也先暂时保留,也不是直接删除,这个也是上面重启出现两个实例名称的原因。
下面我们就来关闭这个注册中心的自我保护机制,来让我们自己决定在什么情况下就可以删除注册的客户端了
注册中心的配置:
server:
port: 7001
spring:
application:
name: eureka-server1
eureka:
instance:
hostname: localhost #本服务实例名称
client:
#需不需要将自己注册到注册中心 false表示不用将注册为server,因为其本身就是server
register-with-eureka: false
#需不需要从注册中心获取其他的服务,由于是服务端,其是维护服务的,所以其也为false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server:
# 设置不自我保留false,默认为true
enable-self-preservation: false
# 有多久没有心跳就删除客户端实例 (单位: ms)
eviction-interval-timer-in-ms: 5000
客户端配置:
server:
port: 7005
eureka:
instance:
hostname: localhost
# 主机ID
instance-id: eureka-client7005
# 展示主机IP
prefer-ip-address: true
# 表示多久向注册中心发生一次心跳
lease-renewal-interval-in-seconds: 1
# 心跳的到期时间
lease-expiration-duration-in-seconds: 2
# 主机IP
client:
# 从注册中心获取注册信息
fetch-registry: true
# 将本服务注册到注册中心
register-with-eureka: true
service-url:
defaultZone: http://localhost:7001/eureka
spring:
application:
name: eureka-client
可以看到这里主要是设置了4个属性,注册中心与客户端分别的两个。这个就能我们自己看着多久删除实例了。
四、OpenFeign使用
首先我们需要知道OpenFeign是用来干什么的,我们使用微服务一般是会在两个服务之间进行服务调用,这个调用一般是可以使用Http请求,但在微服务中我们一般是不会自己自己去写Http请求来获取&解析返回结果的。在微服务的整个生态中一般会有组件来封装这个Http请求,来将这些http请求直接封装为接口调用的形式,让你无感知Http请求,而是直接以接口的方式来获取另一个微服务的返回。OpenFeign就是一种怎样的组件,其就是一个接口形式的Http请求,具体的Http实现由OpenFeign内部实现。
1、项目使用
1)、生产者(被请求方)
我们先在原来的EurekaClient1
提供一个Controller
方法。
@RestController
public class Client1Controller {
@Value("${server.port}")
private Long nowPort;
@RequestMapping(value = "getClientInfo",method = RequestMethod.GET)
public String getClientInfo(@RequestParam("name") String name)
{
return name + " request client, now port is : "+ nowPort;
}
}
然后我们启动,请求http://localhost:7005/getClientInfo
,就能获取当前的返回:
now port is : 7005
2)、消费者(请求方)
现在我们来创建client2
项目,所有的POM
&application.yml
都与client1
项目相同,但我们需要改下配置文件的端口,我们改为7006
,以及实例id(instance-id
)。下面我们来写下client2
的Controller
,用其使用OpenFeign
来调用client1
的方法。
要使用OpenFeign
我们首先需要引入maven依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后在Application
类中添加注解@EnableFeignClients
。
然后我们来写Controller
&Service
的内容:
@RestController
public class Client2Controller {
@Autowired
private FeignServiceClient feignServiceClient;
@RequestMapping(value = "client2/getClientInfo",method = RequestMethod.GET)
public String getClientInfo(@RequestParam("name") String name)
{
return feignServiceClient.getClientInfo(name);
}
}
@FeignClient(name = "eureka-client") // 被调用的服务名称
public interface FeignServiceClient {
@RequestMapping(value = "/getClientInfo",method = RequestMethod.GET)
String getClientInfo(@RequestParam("name") String name);
}
我们可以看到FeignServiceClient
,其通过@FeignClient
注解,然后写上name
被调研的服务名称,再使用接口结合@RequestMapping
就是一个接口方法就完成了其他服务的调用,同时这个Http请求对于我们来说是透明的,我们直接面向的是一个接口方法。
然后我们请求http://localhost:7006/client2/getClientInfo?name=client2
,就可以看到其调用7005
机器的返回:
client2 request client, now port is : 7005
2、openFeign的属性设置
1)、超时配置
我们在client2
中添加yml
配置:
ribbon:
ReadTimeOut: 5000 #建立连接的超时时间
connectionTimeOut: 5000 # 请求的超时时间
这里为什么是ribbon
开头的呢?因为Feign是集成了ribbon
。
然后我们需要修改client1
中的Controller
方法:
@RestController
public class Client1Controller {
@Value("${server.port}")
private Long nowPort;
@RequestMapping(value = "/getClientInfo",method = RequestMethod.GET)
public String getClientInfo(@RequestParam("name") String name)
{
try {
Thread.sleep(6000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return name + " request client, now port is : "+ nowPort;
}
}
这里我们让它睡眠了6秒钟,我们再通过http://localhost:7006/client2/getClientInfo?name=client2
请求client2
就会报超时异常了:
java.net.SocketTimeoutException: Read timed out
at java.base/java.net.SocketInputStream.socketRead0(Native Method) ~[na:na]
at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[na:na]
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:171) ~[na:na]
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:141) ~[na:na]
at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:246) ~[na:na]
at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:286) ~[na:na]
at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:345) ~[na:na]
五、hystrix的使用
1、hystrix的介绍
hystrix是断路器,一般用于方法调用的降级、熔断,而且一般是用于远程调用的,例如结合OpenFeign
来使用。
2、项目使用
我们所有前面的client2
服务,然后要使用hystrix
我们需要引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1)、简单使用
我们先写一个简单的Service
:
@Service
public class HystrixClientService {
/**
* @see @HystrixProperty的其他属性可以看 {https://github.com/Netflix/Hystrix/wiki/Configuration}
* hystrixExecutionFailure表示这个方法发生异常会调用的方法,然后后面的timeoutInMilliseconds是设置这个方法调用执行 * 的超时时间
* @return
*/
@HystrixCommand(fallbackMethod = "hystrixExecutionFailure",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String hystrixInfo()
{
return "success ";
}
public String hystrixExecutionFailure()
{
return "execution failure !!!";
}
}
然后我们在原来的Controller
再添加另一个方法
@RequestMapping(value = "client2/executionHystrix",method = RequestMethod.GET)
public String executionHystrix()
{
return hystrixClientService.hystrixInfo();
}
我们现在请求http://localhost:7006/client2/executionHystrix
,其返回是:
success
下面我们改下service的方法,添加睡眠4秒钟
/**
* @see @HystrixProperty的其他属性可以看 {https://github.com/Netflix/Hystrix/wiki/Configuration}
* @return
*/
@HystrixCommand(fallbackMethod = "hystrixExecutionFailure",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String hystrixInfo()
{
try {
Thread.sleep(4000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "success ";
}
我们再来请求,前端返回的是
execution failure !!!
后端控制台已经报错了
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.fev.service.HystrixClientService.hystrixInfo(HystrixClientService.java:27)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
同时这里还可以使用一个注解来确定默认的fallback方法DefaultProperties
:
@Service
@DefaultProperties(defaultFallback = "defaultFailure")
public class HystrixClientService {
/**
* @see @HystrixProperty的其他属性可以看 {https://github.com/Netflix/Hystrix/wiki/Configuration}
* @return
*/
/*@HystrixCommand(fallbackMethod = "hystrixExecutionFailure",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})*/
@HystrixCommand
public String hystrixInfo()
{
try {
Thread.sleep(4000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "success ";
}
public String hystrixExecutionFailure()
{
return "execution failure !!!";
}
public String defaultFailure()
{
return "defaultFailure!!!";
}
}
这个如果@HystrixCommand
没有指定方法的话就会使用默认的方法。
2)、结合openFeign
我们前面有一个getClientInfo
方法是调用client1
的,现在我们来结合这个方法(这个方法也会超时,并且配置文件配了超时时间)
@FeignClient(name = "eureka-client")
public interface FeignServiceClient {
@RequestMapping(value = "/getClientInfo",method = RequestMethod.GET)
String getClientInfo(@RequestParam("name") String name);
}
这个方法的注解时使用的FeignClient
,不过其实这个与hystrix
断路器有规范。我们先实现FeignServiceClient
接口:
@Component
public class FeignServiceClientHsytrix implements FeignServiceClient {
@Override
public String getClientInfo(String name) {
return "FeignServiceClientHsytrix Failure !!!";
}
}
然后再处理FeignServiceClient
:
@FeignClient(name = "eureka-client",fallback = FeignServiceClientHsytrix.class)
public interface FeignServiceClient {
@RequestMapping(value = "/getClientInfo",method = RequestMethod.GET)
String getClientInfo(@RequestParam("name") String name);
}
可以看到这个方法我们在FeignClient
中添加了其fallback
的处理类,这个其实就达到了异常服务降级的解耦。
然后我们在启动的Application
类添加@EnableHystrix
注解,同时在application.yml
添加:
feign:
hystrix:
enabled: true
来开启feign
与hystrix
的配合:
下面我们请求http://localhost:7006/client2/getClientInfo?name=client2
,就可以看到:
FeignServiceClientHsytrix Failure !!!
2)、其他匹配
hystrix:
command:
default:
circuitBreaker:
# 一个窗口中至少达到的请求数量
requestVolumeThreshold: 5
# 当失败的比例达到这个的时候就熔断
errorThresholdPercentage: 60
# 拒绝请求到再次确认是否关闭断路器的时间
sleepWindowInMilliseconds: 10000
# 强制关闭断路器,即使 有达到超时要求
forceClosed: false
# 强制打开断路器, 会拒绝所有的调用
forceOpen: false
# execution:
# isolation:
# thread:
#熔断器超时时间
# timeoutInMilliseconds: 5000
上面就是表示,如果在单位时间内容的请求数能有5个并且请求超时失败的比例达到60%,就开启断路器,然后在10后,再来执行判断看是继续熔断,还是服务已经能连通了。
3)、hystrix监控版
我们要使用监控版需要引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
然后在启动类Application
添加@EnableHystrixDashboard
,并且还要注入一个bean
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrix
@EnableHystrixDashboard
public class EurekaClientApplication2 {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication2.class,args);
}
/**
* 解决在hystrix 监控界面的 Unable to connect to Command Metric Stream 问题
* @return
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
然后我们就能通过http://localhost:7006/hystrix
看到监控界面:
然后我们输入监控的地址http://localhost:7006/hystrix.stream
,同时加快延迟时间:
我们点击就能进入监控界面,(可能会出现界面在leading状态),这个时候我们随便请求下controller
的方法就能看到界面了
然后我们请求多个方法:
这里橙色表示的是具体的接口,例如我们这里请求了3个方法,就有三块。然后左右的6种红色的就是对应的数量,例如接口请求成功的数量,接口请求失败的数量。关于这个界面具体的介绍已经有很多博文了,这里就不再赘叙了。
六、Spring Cloud Config的使用
1、简单介绍
Spring Cloud Config 就是一个配置中心,在微服务集群环境下其是一个配置中心,其他的微服务可以将它的配置文件都放在这里,在启动的时候就统一从配置中心获取。Spring Cloud Config 配置中心可以从git这些项目管理工具上获取,也可以从本地获取。
2、单配置中心项目创建
我们先创建一个新项目作为配置中心服务
1)、POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.fev</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-config-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
</project>
2)、bootstrap.yml
我们这里使用的配置文件与前面不同,是命名为bootstrap.yml
,项目启动的是是最先加载bootstrap.yml
文件,之后再是application.yml
以及是其他的配置文件。
server:
port: 8000
spring:
application:
name: config-server
cloud:
config:
# 配置与加载可以查看:https://www.springcloud.cc/spring-cloud-greenwich.html#_spring_cloud_config_server
server:
git:
# git 仓库地址
uri: https://gitee.com/{你的git名称,目前这个是使用的国内的码云}/spring-config-server.git
# 搜索的子目录 (注意这里还会同时加载获取上级目录配置文件的内容)
search-paths: dev
# 连接超时
timeout: 10
# git 账号 公共项目一般不需要
username:
# git 密码
password:
3)、Application类
@SpringBootApplication
@EnableConfigServer
public class EurekaConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConfigServerApplication.class,args);
}
}
3、git项目创建
我们去码云创建一个git项目,然后直接在git项目下新建一个application.yml
文件。
common:
tag: version-common-1
然后再建一个子目录dev
,再在这个目录下面新建两个文件client1.yml
、eureka-client.yml
(用于之后我们用client1项目连接这个配置中心获取配置文件内容)。
client1.yml文件
client:
tag: version1
eureka-client.yml文件
application:
tag: eureka-client-version-1
4、项目测试
现在我们启动项目
1)、eureka-client.yml
我们通过http://localhost:8000/eureka-client.yml
,来请求就可以从界面看到我们配置中心eureka-client.yml
文件的内容了,同时我们可以看到其也有加载上级目录application.yml
文件。
application:
tag: eureka-client-version-1
common:
tag: version-common-1
同时我们也可以通过http://localhost:8000/eureka-client.properties
请求来看到另一种格式的内容:
application.tag: eureka-client-version-1
common.tag: version-common-1
2)、client1.yml
不过这里我们再通过http://localhost:8000/client1.yml
来查看client1.yml
文件时会发现这里会404,并不能读取,这里应该是其内部的访问机制,我们可以通过http://localhost:8000/client1-a.yml
,也就是加一个-a
的后缀就能访问:
client:
tag: version1
common:
tag: version-common-1
同理通过http://localhost:8000/application-a.yml
就能获取到application.yml
文件。
common:
tag: version-common-1
5、访问文件的格式拼接
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
官方给出的规则是这个:application
-应用名称(文件前缀名称)、profile
-激活的环境(拼接的后缀),lable
-表示分支名称。例如一个项目要加载,可以写两个文件都会加载,例如application.yml
、application-dev.yml
。
6、其他项目配置中心连接获取
我们以原来的eureka-client1
项目来改造
1)、POM依赖
我们新增一个依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2)、配置文件
我们需要将原来的配置文件名称application.yml
修改为bootstrap.yml
,同时在配置文件中添加:
spring:
application:
name: eureka-client
cloud:
config:
# 配置中心地址
uri: http://localhost:8000
# 加载的文件名称(一般是应用名称),加载的时候会自动拼接后缀 yml或 properties
name: eureka-client,client1
# name: eureka-client
# 分支
label: master
# 当前激活的环境,也就是格式拼接例如我们可以新建一个文件 eureka-client-dev.yml
profile: dev
这里的spring.cloud.config.name
我们可以加载多个文件
3)controller类
@RestController
public class ConfigController {
@Value("${client.tag}")
private String clientTag;
@Value("${application.tag}")
private String applicationTag;
@GetMapping("getClient")
public String getClient()
{
return clientTag;
}
@GetMapping("getApplication")
public String getApplication()
{
return applicationTag;
}
}
我们访问这两个路径就能获取到配置的属性值了。
4)、新建eureka-client-dev.yml文件
然后我们再在git仓库的dev
子目录下面新建一个文件eureka-client-dev.yml
,添加属性:
dev:
eureka-client-dev: eureka-client-dev-version-1
然后我们通过http://localhost:8000/eureka-client-dev.yml
访问:
application:
tag: eureka-client-version-1
common:
tag: version-common-1
dev:
eureka-client-dev: eureka-client-dev-version-1
可以看到其会同时获取到eureka-client.yml
文件的内容,但并没有获取client1
文件的内容。同时我们使用http://localhost:8000/eureka-client.yml
访问的时候没有eureka-client-dev.yml
的内容。
5)、eureka-client1项目改造
我们再修改Controller:
@RestController
public class ConfigController {
@Value("${client.tag}")
private String clientTag;
@Value("${application.tag}")
private String applicationTag;
@Value("${dev.eureka-client-dev}")
private String clientDev;
@GetMapping("getClient")
public String getClient()
{
return clientTag;
}
@GetMapping("getApplication")
public String getApplication()
{
return applicationTag;
}
@GetMapping("getClientDev")
public String getClientDev()
{
return clientDev;
}
}
然后重启通过http://192.168.152.1:7005/getClientDev
就能直接获取到eureka-client-dev-version-1
。不用再修改bootstrap.yml
的name为eureka-client,client1,eureka-client-dev
。
7、配置中心集成到eureka注册中心
我们前面的demo是简单的使用,并没有依赖eureka注册中心,例如我们的配置中心并没有注册到注册中心,同时我们的eureka-client1项目获取配置中心是直接用http://localhost:8000
这个url。现在我们就来将配置中心注册到注册中心,同时将client1项目获取改为应用名称,这个如果我们配置中心高可用,就能通过这个应用名称从注册中心获取到所有所有的配置中心集群,即使其中一台机器的配置中心服务挂了,还可以从其他机器获取到配置中心的内容。
1)、配置中心项目修改
我们先引用一个依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后在Application
类添加注解@EnableEurekaClient
注册到eureka注册中心。
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class EurekaConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConfigServerApplication.class,args);
}
}
再修改配置文件,添加注册中心的内容
server:
port: 8000
spring:
application:
name: config-server
cloud:
config:
# 配置与加载可以查看:https://www.springcloud.cc/spring-cloud-greenwich.html#_spring_cloud_config_server
server:
git:
# git 仓库地址
uri: https://gitee.com/feverasa/spring-config-server.git
# 搜索的子目录 (注意这里还会同时加载获取上级目录配置文件的内容)
search-paths: dev
# 连接超时
timeout: 10
# git 账号 公共查看一般不需要
username:
# git 密码
password:
eureka:
instance:
hostname: localhost
# 主机ID
instance-id: config-server8000
client:
# 从注册中心获取注册信息
fetch-registry: true
# 将本服务注册到注册中心
register-with-eureka: true
service-url:
# defaultZone: http://localhost:7001/eureka,http://localhost:7001/eureka
defaultZone: http://localhost:7001/eureka
启动项目,通过http://localhost:7001/
就能看到配置中心的注册
2)、eureka-client1项目修改
对于client1项目的修改,我们需要修改原来的配置文件内容:
spring:
application:
name: eureka-client
cloud:
config:
# 配置中心地址
# uri: http://localhost:8000
# 加载的文件名称(一般是应用名称),加载的时候会自动拼接后缀 yml或 properties
name: eureka-client,client1
# name: eureka-client
# 分支
label: master
# 当前激活的环境,也就是格式拼接例如我们可以新建一个文件 eureka-client-dev.yml
profile: dev
discovery:
#开启配置中心的服务发现
enabled: true
service-id: config-server #config-sever项目配置的spring.application.name的值
可以看到我们注释原来的uri
了,添加了discovery
的两个属性enabled
&service-id
。重启项目,我们就再访问ConfigController
类的方法,同样能获取到配置的内容。
8、配置中心本地获取配置文件
我们现在新建项目让配置中心从本地加载,其他的POM
、以及Application
的类都与原来的配置中心服务相同,但我们需要修改bootstrap.yml
文件,以及在本地新建一个文件夹放文件,文件夹的话我们保持与原来的git了警方相同
1)、bootstrap.yml文件
server:
port: 8001
spring:
application:
name: config-server
profiles:
active: native
cloud:
config:
server:
native:
# 搜索的本地路径
search-locations: file:D:\PracticeProject\SpringCloudDemo\EurekaConfigServer2\src\main\java\config\dev
eureka:
instance:
hostname: localhost
# 主机ID
instance-id: config-server8001
client:
# 从注册中心获取注册信息
fetch-registry: true
# 将本服务注册到注册中心
register-with-eureka: true
service-url:
# defaultZone: http://localhost:7001/eureka,http://localhost:7001/eureka
defaultZone: http://localhost:7001/eureka
我们启动项目(为了不影响,我们将原来的8000端口配置服务关闭)访问http://localhost:8001/eureka-client.yml
:
application:
tag: eureka-client-version-1
可以看到这里与我们原来的git不同的是,其不能再加载根路径下的文件application.yml
了(我们已经具体指定到dev了,所以需要将application.yml
文件移到dev目录下)。
我们不需要修改原来的client1,重新重启,同样能获取配置文件的值。
目前我们如果我们修改了配置文件,其他服务需要重启才能加载,我们可以修改将其手动刷新,还可以通过bus
消息总线来让其自动刷新,这里就先不再拓展了。