SpringCloud入门搭建
环境搭建
这里使用idea, gradle常见spring cloud 工程。
首先在idea中创建一个Gradle的空项目,作为父工程。
创建完项目后我们修改build.gradle配置文件,设置Springboot,SpringCloud版本,公用属性
buildscript {
ext {
springBootVersion = '2.3.7.RELEASE'
springBootManagementVersion = '1.0.10.RELEASE'
springCloudVersion = 'Hoxton.SR10'
}
repositories {
mavenLocal() //1.优先查找本地maven库,性能最好
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
mavenCentral()//3.最后查找maven中央库
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("io.spring.gradle:dependency-management-plugin:${springBootManagementVersion}")
}
}
allprojects {
group "com.zlennon"
version "1.0.0"
}
subprojects {
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenLocal() //1.优先查找本地maven库,性能最好
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
mavenCentral()//3.最后查找maven中央库
}
dependencies {
testCompile(
"org.springframework:spring-test",
"junit:junit:4.12"
)
}
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" }
}
}
完成之后我们可以执行gradle build 或在idea中执行构建。
既然是微服务,我们先创建一个简单的服务提供这和服务消费者。在父项目下创建模块covid-provider和covid-cosumer
将这两个模块加入到父工程当中
rootProject.name = 'springcloud'
include ':covid-consumer'
include ':covid-provider'
修改各个模块的application.yml配置文件
//消费者
server:
port: 8081
servlet:
context-path: /
api:
url:
prefix : http://localhost:8080/api/covid/
//提供者
server:
port: 8080
servlet:
context-path: /
error:
whitelabel:
enabled : false
spring:
application:
name: ms-covid-provider-8080
datasource:
url: jdbc:mysql://127.0.0.1:3306/springcloud?serverTimezone=UTC&useSSL=false
username: root
password: 123456
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
服务提供放创建响应的module,,service,repository,api访问接口供消费者调用
@RestController
@RequestMapping("/api/covid")
public class CovidController {
@Autowired
CovidService covidService;
@GetMapping("/findAll")
private List<Covid> findAll(){
return covidService.findAll();
}
@PostMapping("/saveDailyData")
private void saveDailyData(){
covidService.saveDailyData();
}
}
消费者方
@RestController
@RequestMapping("/covid")
public class CovidController {
@Autowired
CovidService covidService;
@Autowired
RestTemplate restTemplate;
@Value("${api.url.prefix}")
String apiUrl;
@GetMapping("/findAll")
private List<Covid> findAll(){
return Arrays.asList(restTemplate.getForObject(apiUrl+"findAll",Covid[].class)) ;
}
@PostMapping("/saveDailyData")
private void saveDailyData(){
restTemplate.postForEntity(apiUrl+"saveDailyData",null,String.class);
}
}
启动两个springboot,使用消费者服务连接访问http://localhost:8080/covid/findAll。有了服务提供者我们就可以直接调用服务了,但是如果服务非常多的化,很难记住每个服务的ip和端口,也不知道每个服务是干什么的。这个时候就需要将服务统一注册管理,接下来将服务注册到Enreka服务注册中心。
服务注册
新创建服务注册模块 server-registry
导入依赖包 ` implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'`
配置Eureka服务注册中心
server:
port: 9001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动应用,访问http://localhost:9001/ ,看如如下界面Eureka已配置正确
将服务提供者注册到Eureka
引入依赖compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
在启动类加注解
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:9001/eureka/
instance:
instance-id: ms-cloud-covid-8080
prefer-ip-address: true #访问路径可以显示IP地址
在消费者方配置
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:9001/eureka/
当我们再次访问Eureka时,就会发现已注册的服务实例
使用Consul作为注册中心
需要的依赖implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ms-covid-provider-consul
启动注解类@EnableDiscoveryClient
既然服务已经注册到Eureka,就需要到服务中心去找对应的服务,怎么找到对应的服务呢,这个时候就需要Ribbon或Feign 闪亮登场了,Ribbon是一个客户端的负载均衡组件,Feign是一个声明式WebService客户端.
负载均衡查找服务
- ribbon
引入ribbon依赖
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon'
由于掉远程服务使用的是rest 所以我们在RestTemplate加上配置,@LoadBalanced 通过负载均衡查找服务
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
将客户端调用的的服务连接改为Eureka中的服务连接
http://ms-covid-provider-8080/api/covid/
将客户端标记为RibbonClient
@RibbonClient("ms-covid-consumer-8081")
-
Feign
依赖 implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
申明接口
@RestController
@RequestMapping("/covid")
public class CovidController {
@Autowired
FeignClientService feignClientService;
@GetMapping("/findAll")
private List<Covid> findAll(){
return feignClientService.findAll() ;
}
@PostMapping("/saveDailyData")
private void saveDailyData(){
feignClientService.saveDailyData();
}
}
---------------------------------------------------------------------
@FeignClient(value = "ms-covid-provider-8080",path = "/api/covid")
public interface FeignClientService {
@RequestMapping("/findAll")
public List<Covid> findAll();
@RequestMapping("/saveDailyData")
public void saveDailyData();
}
启动类标记客户端@EnableFeignClients()。
Spring Cloud Hystrix熔断
在分布式系统中服务之间会存在级联调用,加入其中某些服务异常,将会使一条线上的调用超时或失败,进而可能造成请求的大量堆积。Hystrix通过添加延迟,容错,提供备选项 可以提高系统的整体弹性。
引入依赖 implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
配置文件中 开启熔断
feign:
hystrix:
enabled: true
在主启动类添加 @EnableHystrix或@EnableCircuitBreaker注解
- 使用@HystrixCommand
HystrixCommand 方式很简单,@HystrixCommand(fallbackMethod = "findCovidFail") ,添加注解并设置调用异常时的处理方法。若果方法较多的话这多处理方法非常繁琐。
-
使用fallbackFactory
feigin申明式调用
@FeignClient(value = "ms-covid-provider-8080",path = "/api/covid",fallbackFactory=CovidFallbackFactory.class)
public interface FeignClientService {
@RequestMapping("/findAll")
public List<Covid> findAll();
@RequestMapping("/findById/{id}")
public Covid findById(@PathVariable(value="id") Integer id);
}
失败回调工厂
@Component
public class CovidFallbackFactory implements FallbackFactory<FeignClientService> {
Logger logger = LoggerFactory.getLogger(getClass());
@Override
public FeignClientService create(Throwable cause) {
return new FeignClientService() {
@Override
public List<Covid> findAll() {
return Collections.emptyList();
}
@Override
public Covid findById(Integer id) {
logger.error(cause.toString());
return new Covid();
}
};
}
}
完成配置后我们启动服务测试,根据id查找不到数据的会抛异常,进而会调用我们出错情况下的处理方法。
Spring Cloud 网关
微服务部署以后,当请求当来后就可以提供服务了,但是这些请求中可能包含不正常的请求,或者请求不能找到正确的服务,就像每个组织机构一样,都会设置一个前台接待客人,前台人员可以带着你找到你组织其他部门不至于迷路。spring cloud gateway为我们提供了这样一套机制,实现请求的路由,转发,校验等。
创建一个spring boot gateway模块
引入依赖
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
修改
server:
port: 7002
spring:
application:
name: covid-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: covid-route #注意id前面的-需要
uri: http://localhost:8080
predicates:
- Path=/api/covid/**
启动服务提供者8080,gateway 测试访问 http://localhost:7002/api/covid/findAll,可以访问,说明在访问/api/covid/**这样的路径是请求将被转发到8080上。
因为我们的服务都已经注册到了Eureka,那么就需要gateway到Eureka上找到请求对应的服务。 所以呢gateway应用也注册到Eureka中,这样gateway就能找到Eureka中的其他服务了。
完整的配置文件,同时启动类要标记为@EnableEurekaClient
server:
port: 7002
spring:
application:
name: covid-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: covid-route
uri: lb://ms-covid-provider-8080
predicates:
- Path=/api/covid/**
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:9001/eureka/
instance:
instance-id: ms-cloud-gateway
prefer-ip-address: true #访问路径可以显示IP地址
访问http://localhost:7002/api/covid/findAll能够成功。
后台打印如下语句
DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client ms-covid-provider-8080 initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ms-covid-provider-8080,current list of Servers=[192.168.3.4:8080],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
说明通过负载均衡找到了配置的服务。好了我们最简单的微服务已经配置好了,准备部署上线了,但是可能代码中只配置了开发环境的配置,生产环境有一些密码什么的不希望让开发人员看到,如果要让运维人员手动去改,少了还好,几百个微服务就麻烦了,能把运维人员给累死。并且开发的过程想要修改配置文件需要重启应用。这个时候就需要SpringCould的分布式配置中心了。
Spring Cloud Config 分布式配置中心
Spring Cloud Config是通过git 管理的,所以我们需要在Github一个仓库存放配置信息。仓库创建好了之后,需要创建一个Spring Cloud 配置服务,用来连接github访问上面的配置信息。
导入需要的包
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
配置git仓库信息 ,包含如下文件
server:
port: 7003
spring:
application:
name: cloud-config-server
cloud:
config:
server:
git:
uri: https://github.com/lennonn/spring-cloud-config
search-paths: /
使用@EnableConfigServer开启配置服务,启动访问我们的配置信息 http://localhost:7003/application-providerconfig.yml ,能访问到说明配置正确。
客户端需要获取配置中心的文件访问,所以需要配置客户端以找到配置文件,需要创建一个bootstrap.yml,并且需要引入依赖
implementation 'org.springframework.cloud:spring-cloud-starter-config'
spring:
cloud:
config:
name: application-providerconfig #需要从github上读取的资源名称,注意没有yml后缀名
profile: dev #本次访问的配置项
label: master
uri: http://localhost:7003
上面的配置说明我们的客户端去配置中心(http://localhost:7003)找一个文件名叫application-providerconfig.yml的文件
开启客户端,下面的输出证明已经拿到配置文件
09:42:19.682 [main] INFO org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.getRemoteEnvironment - Fetching config from server at : http://localhost:7003
09:42:22.536 [main] INFO org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.log - Located environment: name=application-providerconfig, profiles=[dev], label=master, version=40a4c183499f7a1ddf76ffb4758c1d33be5775e7, state=null
总结
在上面我们搭建了最简单的SpringCloud应用,使用了它的基本组件,每个组件都是单个服务的,这样的应用显然不具备高可用性,同时分为多个组件增加了系统复杂性,为了构建高可用的分布式应用,我们之后需要部署为集群方式。
分享到: