教程"/>
springCloud搭建详细教程
springCloud搭建详细教程
别的都不说了,直接动手:
SpringCloud分布式开发五大组件详解
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config 本文暂不涉及config
个人版本的初级springcloud总体结构
我们从服务发现开始
1.Netflix Eureka
1.1我们先创建一个空的maven项目
里面除了父pom什么也不需要
1.2新建一个module,搭建注册中心服务端
引入依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.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><!--管理依赖--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Finchley.M7</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies><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>;/url><snapshots><enabled>false</enabled></snapshots></repository></repositories>
配置文件:
server:port: 8101
eureka:instance:##注册中心的ip地址hostname: 127.0.0.1client:service-url: ##注册中心地址defaultZone: http://${eureka.instance.hostname}:8101/eureka###自己是注册中心,是否要将自己注册到注册中心去,但是集群的时候需要设置为trueregister-with-eureka: false###自己是注册中心,不需要去检索服务信息fetch-registry: false
在启动类上需要加@EnableEurekaServer注解,支持eureka服务端
启动eureka服务:
1.3 member和order(eureka客户端)环境的搭建
引入依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0" xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.example</groupId><artifactId>spring-cloud-20201122</artifactId><version>1.0-SNAPSHOT</version></parent><groupId>org.example</groupId><artifactId>order</artifactId><version>0.0.1-SNAPSHOT</version><name>order</name><description>订单系统 模块</description><!--管理依赖--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Finchley.M7</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><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-tomcat</artifactId><!--<scope>provided</scope>--></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
配置文件
###订单服务端口号
server:port: 9200
###服务别名---服务注册到注册中心的名称
spring:application:name: sean-order
eureka:client:service-url:###当前订单服务注册到eureka服务地址defaultZone: http://127.0.0.1:8101/eureka###是否需要注册到eureka上register-with-eureka: true###需要检索服务fetch-registry: true
启动类注解上添加 @EnableEurekaClient
1.4 使用restTemplate实现服务之间的调用
注入RestTemplate: spring容器中默认是没有RestTemplate对象的,需要自己放入容器,不然会报错:
启动的时候将这个对象放入spring容器中
@Beanpublic RestTemplate getRestTemplate() {return new RestTemplate();}
使用RestTemplate远程调用:
1、url使用ip:这种方式存在的问题就是如果我这个服务的服务器ip换了,那么大量代码需要修改。
2、url使用eureka的Status中的名字(http://laptop-7hmp32ro:9100):这种方式个人觉得也存在问题,因为如果这个服务需要重启的话,这个名字可能会发生改变,造成的结果和使用ip是一样的
3、url使用服务别名:这种方式需要注意的是RestTemplate注入的时候需要增加一个注解@LoadBalanced
@Bean// 如果要使用注册中心的服务别名访问// 或者想使用本地负载均衡,就必须要加这个注解@LoadBalancedpublic RestTemplate getRestTemplate() {return new RestTemplate();}
@LoadBalanced: 如果服务之间的调用需要使用服务别名的话,RestTemplate注入的时候需要增加这个注解,另外,使用ribbon做服务本地负载均衡的时候也需要使用这个注解。
编写业务逻辑:
@RestController
public class OrderApi {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/getorder")public String getorder() {// 调用member服务// url一般使用的都是eureka中心的地址// String url1="http://127.0.0.1:9100/getmember";// 使用status里面点开的地址也能访问,但是这个地址是随机给的// String url2 = "http://laptop-7hmp32ro:9100/getmember";// 使用eureka中的服务器别名调用// 但是这样需要一个注解:@LoadBalanced配置在restTemplate实体对象// 这样就能使用服务别名进行访问,而且使restTemplate具有客户端负载均衡能力// 服务别名不区分大小写String url = "http://mzd-member/getmember";String result = restTemplate.getForObject(url, String.class);return result;}
}
@RestController
public class MemberApi {@RequestMapping("/getmember")public String Member() {return "这里是会员服务" ;}
}
实验结果:
到这里我们的初步搭建就完成了,我们回顾一下,上面我们在一个空的父工程下搭建了三个模块,其中一个Eureka我们当做注册中心服务端,一个member会员系统,一个order订单系统,最后我们是使用restTempllate在order服务中掉起memer服务。
2.Netflix Ribbon
服务集群后使用ribbon实现服务本地轮询调用
注意: 首要的肯定就是在RestTemplate上增加@LoadBalanced注解
会员服务集群: 启动两个会员服务(不同的端口),然后接口返回当前服务的端口,方便区别
@RestController
public class MemberApi {// 为了区分负载均衡@Value("${server.port}")private String port;@RequestMapping("/getmember")public String Member() {return "这里是会员服务,端口号为:" + port;}
}
实验结果:
1、确认会员服务是集群的:
2.调用订单接口:
本地测试直接在idea配置两个端口启动同一个服务即可。
3.Netflix Hystrix
ribbon-hystrix断路器
pom.xml增加
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
业务添加熔断的方法
package org.example.order.controller;import comflix.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
public class OrderApi {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/getorder")@HystrixCommand(fallbackMethod = "helloError")public String getorder() {// 调用member服务// url一般使用的都是eureka中心的地址
// String url1="http://127.0.0.1:9100/getmember";// 使用status里面点开的地址也能访问,但是这个地址是随机给的// String url2 = "http://laptop-7hmp32ro:9100/getmember";// 使用eureka中的服务器别名调用// 但是这样需要一个注解:@LoadBalanced配置在restTemplate实体对象// 这样就能使用服务别名进行访问,而且使restTemplate具有客户端负载均衡能力// 服务别名不区分大小写String url = "http://sean-member/getmember";String result = restTemplate.getForObject(url, String.class);return result;}public String helloError(){return "hello!,An Error Has Occurred";}
}
修改主启动类
package org.example.order;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloudflix.eureka.EnableEurekaClient;
import org.springframework.cloudflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}@Bean// 如果要使用注册中心的服务别名访问// 或者想使用本地负载均衡,就必须要加这个注解@LoadBalancedpublic RestTemplate getRestTemplate() {return new RestTemplate();}
}
结果:
先出现交替:
这里是会员服务9100;
这里是会员服务9101;
然后交替出现
这里是会员服务9100;
hello!,An Error Has Occurred;
最后出现
这里是会员服务9100;
4.Netflix Zuul
新建zuul-gateway系统
在上面的pom中添加
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
添加配置文件
server:port: 8768
spring:application:name: server-zuul
eureka:client:service-url:defaultZone: http://127.0.0.1:8101/eureka###是否需要注册到eureka上register-with-eureka: true###需要检索服务fetch-registry: true
# serviceId必须与相应的服务名字对应!
zuul:prefix: /sean #设置统一域名前缀routes:zuul-a:path: /zuul-a/**serviceId: sean-orderzuul-b:path: /zuul-b/**serviceId: sean-member
ribbon:ReadTimeout: 6000000ConnectTimeout: 6000000hystrix:command:c4i-store:execution:timeout:enabled: trueisolation:thread:timeoutInMilliseconds: 6000000ribbon:ReadTimeout: 600000ConnectTimeout: 600000
#如果未配置以上的超时时间 就会comflix.zuul.exception.ZuulException: Forwarding error报错
启动类添加注解 @EnableZuulProxy
访问: http://127.0.0.1:8768/sean/zuul-a/getorder
结果:
Zuul拦截功能
添加一个Myfilter类集成ZuulFilter
package org.example.zuulgateway.config;import comflix.zuul.ZuulFilter;
import comflix.zuul.context.RequestContext;
import comflix.zuul.exception.ZuulException;
import org.springframework.cloudflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@Component
public class Myfilter extends ZuulFilter {// filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:// pre:路由之前// routing:路由之时// post: 路由之后// error:发送错误调用@Overridepublic String filterType() {return "pre";}//filterOrder:过滤的顺序@Overridepublic int filterOrder() {return 0;}//shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。@Overridepublic boolean shouldFilter() {return true ;}//run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。@Overridepublic Object run() throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();HttpServletResponse response = ctx.getResponse();Object password = request.getParameter("password");try {PrintWriter writer = response.getWriter();if(null == password){System.out.println("密码为空!");ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(500);writer.write("error login!");writer.close();return null;}if("123456".equals(password)){System.out.println("登录成功!");ctx.setSendZuulResponse(true);ctx.setResponseStatusCode(200);writer.write("success login!");writer.close();return null;}else{System.out.println("密码错误!");ctx.setSendZuulResponse(true);ctx.setResponseStatusCode(500);writer.write("error login!");writer.close();return null;}} catch (IOException e) {e.printStackTrace();return null;}}
}
重启server-zuul,访问:http://localhost:8768/shawn/zuul-a/hello?name=shawn&password=123
重启server-zuul,访问:http://localhost:8768/shawn/zuul-a/hello?name=shawn&password=123456
更多推荐
springCloud搭建详细教程
发布评论