Spring-Cloud Note
组件
- Eureka
- Ribbon
- Feign
- Hystrix
- Zuul
@SpringCloudApplication
注解
一个Spring Cloud
标准应用包含服务发现以及断路器
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
- @SpringCloudApplication
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableCircuitBreaker
常用服务配置
spring:
application:
name: client #服务名称
server:
port: 9070 #启动端口
eureka:
client:
service-url:
defaultZone: http://localhost:9090/eureka #定义服务注册中心地址
Eureka
-服务注册/发现
配置
server:
port: 9090
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
入口
package com.github.crazyjay97.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
服务发现
客户端可以在入口处加@EnableDiscoveryClient
注解
可以打开 链接访问eureka
UI界面
接口服务
配置
server:
port: 9080
spring:
application:
name: api
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9090/eureka
入口
package com.github.crazyjay97.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
接口控制器
package com.github.crazyjay97.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@RestController
public class Controller {
@RequestMapping("hello")
public String Hello() {
System.out.println("请求处理");
try {
// 模拟任务处理,以及为熔断器做准备
TimeUnit.SECONDS.sleep(new Random().nextInt(3));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "word";
}
}
起多个
api
服务为负载均衡做测试,可以在启动时加-Dserver.port=9081
参数指定端口
ribbon
-客户端负载均衡
配置
spring:
application:
name: client
server:
port: 9000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9090/eureka
package com.github.crazyjay97.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {
@Bean
@LoadBalanced //加载 restTemplate Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
调用接口
package com.github.crazyjay97.client.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("client")
public class Controller {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("hello")
public String hello() {
//API 接口服务的名称,在eureka中以大写显示,这里写成大写
String body = restTemplate.getForEntity("http://API/hello", String.class).getBody();
return "hello" + body;
}
}
hystrix
-断路器
配置
spring:
application:
name: client
server:
port: 9000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9090/eureka
入口
package com.github.crazyjay97.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ClientApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
服务
package com.github.crazyjay97.client.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("client")
public class Controller {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("hello")
@HystrixCommand(fallbackMethod = "errorFallback")
public String hello() {
String body = restTemplate.getForEntity("http://API/hello", String.class).getBody();
return "hello" + body;
}
public String errorFallback() {
return "error";
}
}
可以关掉一个
api
服务然后请求在不加断路器
的情况下请求接口,当请求到已经关闭的api
服务时,会出现500错误,当加断路器
以后会出现处理之后的接口。当服务不可达、超时或故障的时候,触发断路器
的fallback
方法。
feign
-声明式调用
配置
spring:
application:
name: feign-client
server:
port: 9070
eureka:
client:
service-url:
defaultZone: http://localhost:9090/eureka
入口
package com.github.crazyjay97.feignclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients //需要开启feign
@EnableCircuitBreaker
public class FeignclientApplication {
public static void main(String[] args) {
SpringApplication.run(FeignclientApplication.class, args);
}
}
定义接口
package com.github.crazyjay97.feignclient.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("api") //接口服务的名称
public interface ApiService {
@RequestMapping("/hello")
String hello();
}
服务
package com.github.crazyjay97.feignclient.controller;
import com.github.crazyjay97.feignclient.service.ApiService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
@Autowired
private ApiService apiService;
@RequestMapping("hello")
@HystrixCommand(fallbackMethod ="helloFallback")
public String hello() {
return "hello " + apiService.hello();
}
public String helloFallback() {
return "error";
}
}
zuul
-网关服务
配置
zuul:
routes:
api-a-url: #自定义名称
path: /api/** #前缀
url: http://localhost:9070/ #转发的地址
入口
package com.github.crazyjay97;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
config
-配置中心
配置
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/crazyjay97/cloud.git #仓库地址
searchPaths: config #文件于仓库路径
username: root
password: root
server:
port: 9050
依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
入口
package com.github.crazyjay97;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
配置中心客户端
配置-bootstrap.yml
spring:
application:
name: config-client
cloud:
config:
profile: base
label: master
uri: http://localhost:9050
server:
port: 9040
依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
入口
package com.github.crazyjay97;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
控制器
package com.github.crazyjay97.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
@Value("${cloud-version}")
private String version;
@Autowired
private Environment environment;
@GetMapping("getConfig")
public String getConfig() {
return version + "-" + environment.getProperty("cloud-version");
}
}