spring cloud是什么?spring cloud的使用介绍
一、什么是Spring Cloud?
Spring提供了一系列工具,可以帮助开发人员迅速搭建分布式系统中的公共组件(比如:配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,主节点选举, 分布式session, 集群状态)。协调分布式环境中各个系统,为各类服务提供模板性配置。使用Spring Cloud, 开发人员可以搭建实现了这些样板的应用,并且在任何分布式环境下都能工作得非常好,小到笔记本电脑, 大到数据中心和云平台。
Spring Cloud是基于Spring Boot的, 最适合用于管理Spring Boot创建的各个微服务应用。要管理分布式环境下的各个Spring Boot微服务,必然存在服务的注册问题。所以我们先从服务的注册谈起。既然是注册,必然有个管理注册中心的服务器,各个在Spring Cloud管理下的Spring Boot应用就是需要注册的client。
Spring Cloud使用erureka server, 然后所有需要访问配置文件的应用都作为一个erureka client注册上去。eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳,在默认情况下erureka server也是一个eureka client ,必须要指定一个 server。
1.创建Eureka Server
先创建一个spring boot的项目
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> <groupId>me.cn</groupId> <artifactId>test</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>test</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>10</java.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
需要一个注解@EnableEurekaServer加在springboot工程的启动类上
@EnableEurekaServer @SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
eureka server的配置文件appication.yml
server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动eureka server,然后访问http://localhost:8761, 界面如下, "No instances available" 表示无client注册
2.创建一个Eureka Client
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> <groupId>com.chry</groupId> <artifactId>test1</artifactId> <version>0.0.1-SNAPSHOT</version> <name>test1</name> <packaging>jar</packaging> <description>Demo Spring Boot Client</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
使用@EnableEurekaClient注解表明是client
@SpringBootApplication @EnableEurekaClient @RestController public class Test1Application { public static void main(String[] args) { SpringApplication.run(Test1Application.class, args); } @Value("${server.port}") String port; @RequestMapping("/") public String home() { return "hello world from port " + port; } }
yml文件的配置
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8762 spring: application: name: service-helloworld
最后启动client,之后就可以在服务器端口看到该client成功注册
二、配置管理
Spring Cloud的解决方案是, 将这些配置文件放到版本管理服务器里面,Spring Cloud缺省配置使用GIT中。所有Web服务均从GIT中获取这些配置文件。由于GIT服务器与具体Web服务器之间不需要共享存储, 只要网络可达就行,从而可以实现Web服务于配置信息的存放位置的解耦。
2.1创建config Server
pom文件新加了依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
@EnableConfigServer注解说明了一个Config Server。同样我们使用@EnableEurekaClient将它注册到服务中心。
Config server的配置文件appication.yml , 注意配置文件的url是GIT服务器的仓库地址, searchPaths配置文件所在的文件夹在仓库中的路径, 在server端不需要指定具体配置文件名, 因为具体的配置文件是什么有应用(也就是client)决定。
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8888 spring: cloud: config: server: git: uri: https://gitee.com/ning9/CRUD.git searchPaths: spring-cloud/helloworldConfig application: name: config-server
启动Config server,访问http://localhost:8888/config-client-dev.properties就可以显示配置文件内容
2.2创建config client
启动文件
@SpringBootApplication @RestController public class ConfigClientApplication { public static void main(String[] args) { SpringApplication.run(ConfigClientApplication.class, args); } @Value("${hello}") String hello; @RequestMapping(value = "/hello") public String hello(){ return hello; } }
yml文件
spring: application: name: config-client cloud: config: label: master profile: dev uri: http://localhost:8888/ server: port: 8881
启动config-client应用后, 可以访问http://locahost/8881/hello, 可以看到,应用本身并没有直接配置hello的具体内容, 也没指定具体配置文件,所欲这些都由spring cloud框架提交给config server了。
三、配置自动刷新
首先,在pom.xml中添加以下依赖。spring-boot-starter-actuator
是一套监控的功能,可以监控程序在运行时状态,其中就包括/refresh
的功能。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
其次,开启refresh机制, 需要给加载变量的类上面加载@RefreshScope注解
,其它代码可不做任何改变,那么在客户端执行/refresh
的时候就会更新此类下面的变量值,包括通过config client从GIT获取的配置。
@SpringBootApplication @RestController @RefreshScope public class ConfigClientApplication { public static void main(String[] args) { SpringApplication.run(ConfigClientApplication.class, args); } @Value("${hello}") String hello; @RequestMapping(value = "/hello") public String hello(){ return hello; } }
但是这种方式需要自己手动重新运行方法,才能看到更新后的数据
四、分布式环境下自动发现配置服务
将config-server注册到服务中心
将hello world的应用注册到eureka 服务中心, 配置方法同前面一样
修改配置文件,将config-server的URL硬编码机制改成,通过服务中心根据名字自动发现机制
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/spring: application: name: config-client cloud: config: label: master profile: dev discovery: enabled: true service-id: config-server management: security: enabled: falseserver: port: 8881
我们注释掉了硬编码的config-server的URL配置, 取而代之的是服务注册中心的地址http://localhost:8761/eureka/以及配置服务的名字“config-server”, 同时打开自动发现机制discovery.enable = true. 我们在运行一下hello world应用, 可以发现, GIT里面的内容依然可以访问。此时我们的hello world应用已经完全不知道配置服务的地址,也不知道配置的内容, 所有这些都通过服务注册中心自动发现。
五、客户端的负载均衡
Spring Cloud用Ribbon来实现两个Hello World服务的负载均衡
5.1创建ribbon服务
添加pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency>
创建启动类ServiceRibbonApplication
@SpringBootApplication @EnableDiscoveryClient public class ServiceRibbonApplication { public static void main(String[] args) { SpringApplication.run(ServiceRibbonApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
@EnableDiscoveryClient向服务中心注册,并且注册了一个叫restTemplate的bean。
@ LoadBalanced注册表明,这个restRemplate是需要做负载均衡的。
创建获取一个获取Hello内容的service类
@Service public class HelloService { @Autowired RestTemplate restTemplate; public String getHelloContent() { return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class); } }
这里关键代码就是, restTemplate.getForObject方法会通过ribbon负载均衡机制, 自动选择一个Hello word服务,
这里的URL是“http://SERVICE-HELLOWORLD/",其中的SERVICE-HELLOWORLD是Hello world服务的名字,而注册到服务中心的有两个SERVICE-HELLOWORLD。 所以,这个调用本质是ribbon-service作为客户端根据负载均衡算法自主选择了一个作为服务端的SERVICE-HELLOWORLD服务。然后再访问选中的SERVICE-HELLOWORLD来执行真正的Hello world调用。
六、用声明式REST客户端Feign调用远端http服务
添加新的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
创建启动类,需要加上@EnableFeignClients注解以使用Feign, 使用@EnableDiscoveryClient开启服务自动发现
添加配置文件application.yml, 使用端口8902, 名字定义为service-feign, 并注册到eureka服务中心
定义Feign:一个用@FeignClient注解的接口类
@FeignClient
用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired
注入; 该接口通过value定义了需要调用的SERVICE-HELLOWORLD服务(通过服务中心自动发现机制会定位具体URL); @RequestMapping定义了Feign需要访问的SERVICE-HELLOWORLD服务的URL(本例中为根“/”)
@FeignClient(value = "SERVICE-HELLOWORLD") public interface HelloWorldService { @RequestMapping(value = "/",method = RequestMethod.GET) String sayHello(); }
Spring Cloud应用在启动时,Feign会扫描标有@FeignClient
注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate
对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里
编写一个Controller。
注入之前通过@FeignClient定义生成的bean,
sayHello()映射到http://localhost:8902/hello, 在这里,我修改了Hello World服务的映射,将根“/”, 修改成了“/hello”。
@RestController public class WebController { @Autowired HelloWorldService helloWorldFeignService; @RequestMapping(value = "/hello",method = RequestMethod.GET) public String sayHello(){ return helloWorldFeignService.sayHello(); } }
七、断路器
7.1在Ribbon应用中使用断路器
先添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
在Spring Boot启动类上添加@EnableCircuitBreaker注解
用@HystrixCommand注解标注访问服务的方法
@Service public class HelloService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "serviceFailure") public String getHelloContent() { return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class); } public String serviceFailure() { return "hello world service is not available !"; } }
@HystrixCommand注解定义了一个断路器,它封装了getHelloContant()方法, 当它访问的SERVICE-HELLOWORLD失败达到阀值后,将不会再调用SERVICE-HELLOWORLD, 取而代之的是返回由fallbackMethod定义的方法serviceFailure()。@HystrixCommand注解定义的fallbackMethod方法,需要特别注意的有两点:
第一, fallbackMethod的返回值和参数类型需要和被@HystrixCommand注解的方法完全一致。否则会在运行时抛出异常。比如本例中,serviceFailure()的返回值和getHelloContant()方法的返回值都是String。
第二, 当底层服务失败后,fallbackMethod替换的不是整个被@HystrixCommand注解的方法(本例中的getHelloContant), 替换的只是通过restTemplate去访问的具体服务。可以从中的system输出看到, 即使失败,控制台输出里面依然会有“call SERVICE-HELLOWORLD”。
7.2在Feign应用中使用断路器
用@FeignClient注解添加fallback类, 该类必须实现@FeignClient修饰的接口。
@FeignClient(name = "SERVICE-HELLOWORLD", fallback = HelloWorldServiceFailure.class) public interface HelloWorldService { @RequestMapping(value = "/", method = RequestMethod.GET) public String sayHello(); }
创建HelloWorldServiceFailure类, 必须实现被@FeignClient修饰的HelloWorldService接口。注意添加@Component或者@Service注解,在Spring容器中生成一个Bean
@Component public class HelloWorldServiceFailure implements HelloWorldService { @Override public String sayHello() { System.out.println("hello world service is not available !"); return "hello world service is not available !"; } }
在application.yml中添加如下配置:
feign: hystrix: enabled: true
八、路由网管zuul
创建新的工程添加新的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
创建启动类: 使用@EnableZuulProxy注解
@EnableZuulProxy @EnableEurekaClient @SpringBootApplication public class ServiceZuulApplication { public static void main(String[] args) { SpringApplication.run(ServiceZuulApplication.class, args); } }
编写zuul服务配置:
简单配置两个路由, 一个路由到ribbon,一个路由到feign; 由于都注册到eureka服务中心,所以都用通过serviceId来发现服务具体地址, path是路由的地址映射关系
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8904 spring: application: name: service-zuul zuul: routes: ribbo: path: /api-ribbon/** serviceId: service-ribbon feign: path: /api-feign/** serviceId: service-feign
这时启动zuul服务, 然后访问http://localhost:8904/api-ribbon可直接路由到http://localhost:8901/.
http://localhost:8904/api-feign/hello可路由到http://localhost:8902/hello
zuul还提供了过滤功能, 只要实现接口ZuulFilter即可对请求先进行筛选和过滤之后再路由到具体服务。
以上就是spring cloud是什么?spring cloud的使用介绍的详细内容,更多请关注其它相关文章!
推荐阅读
-
Spring Cloud Feign文件传输的示例代码
-
Spring Cloud实现提供API给客户端的方法详解
-
spring cloud 之 Feign 使用HTTP请求远程服务的实现方法
-
Spring Cloud 配置中心内容加密的配置方法
-
详解使用spring boot admin监控spring cloud应用程序
-
使用Spirng Boot Admin监控Spring Cloud应用项目
-
Spring Cloud中Eureka开启密码认证的实例
-
使用IntelliJ IDEA 2017.2.5 x64中的Spring Initializr插件快速创建Spring Boot/Cloud工程(图解)
-
Spring cloud restTemplate 传递复杂参数的方式(多个对象)
-
详解Spring Cloud中Hystrix的请求合并