一、SpringCloud架构流程如下:
二、创建“服务注册中心(server)”
1、选择“New”,在对话框中选择“Spring Boot”——“Spring Starter Project”,点击“Next”
2、在“New Spring Starter Project”对话框中填写以下内容,点击“Next”
3、选择勾选“Eureka Server”
插件
如果未勾选,则在pom.xml文件添加eureka-server依赖包
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
4、在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,只需要在application.properties
中问增加如下配置:
spring.application.name=server
server.port=1111
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
5、通过@EnableEurekaServer
注解启动一个服务注册中心提供给其他应用进行对话
//启动开关
@EnableEurekaServer
6、启动工程后,访问:http://localhost:1111/
,可以看到此时的页面还没有任何服务
三、创建服务提供方(Client)
1、创建一个名为Client项目工程
2、勾选Eureka Discovery Client 和springWeb
插件
如未勾选,则在pom.xml文件加入eureka-client依赖包
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
点击fishes完成!
3、创建一个Ctroller类,实现/add请求处理接口,通过DiscoveryClient对象,在日志中打印出服务实例的相关内容。
@RestController
public class ComputeController {
@RequestMapping("/add")
public Integer add(Integer a, Integer b) {
System.out.println(a + "+" + b + "=" + (a+b));
return a+b;
}
}
4、在主类中通过加上@EnableDiscoveryClient
注解,该注解能激活Eureka中的DiscoveryClient实现,才能实现Controller中对服务信息的输出。
@EnableDiscoveryClient
@SpringBootApplication
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
5、完成了服务内容的实现之后,再继续对application.properties做一些配置工作,具体如下:
# 应用名称
spring.application.name=Client
# 应用服务 WEB 访问端口
server.port=8080
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
6、启动该工程后,再次访问:http://localhost:1111/
,以下界面就成功了!
四、使用Ribbon(Ribbon是一个基于HTTP和TCP客户端的负载均衡器)、Feign(Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单)来实现客户端负载均衡的消费者
准备工作:
启动服务注册中心:server
启动服务提供方:Client,同时,启动两个Client中的端口server-port为8081、8082
此时访问:http://localhost:1111/
此时,2个端口已启动
4.1、使用Ribbon实现负载均衡
1、新建一个Spring Starter Project工程
如未勾选,则在pom.xml文件加入依赖包
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、在应用主类中,通过@EnableDiscoveryClient注解来添加发现服务能力。创建RestTemplate实例,并通过@LoadBalanced注解开启均衡负载能力。
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
3、创建ConsumerController来消费CLIENT的add服务。通过直接RestTemplate来调用服务,计算10 + 20的值。
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Integer add(Integer a,Integer b) {
Integer result = rt.getForEntity("http://CLIENT/add?a="+ a + "&b=" + b , Integer.class).getBody();
return result;
}
4、application.properties中配置eureka服务注册中心
# 应用名称
spring.application.name=Ribbon
# 应用服务 WEB 访问端口
server.port=8083
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
5、启动该应用,连续访问4次:http://localhost:8083/add?a=10&b=8
当访问4次时,会均衡的分到2个端口上,如下图:
五、断路器
1、什么是断路器?
“断路器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,“断路器”能够及时的切断故障电路,防止发生过载、发热、甚至起火等严重后果。
2、Netflix Hystrix:在Spring Cloud中使用了Hystrix 来实现断路器的功能。
3、在Robbin中的pom.xml中引入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
4、在eureka-ribbon的主类RibbonApplication
中使用@EnableCircuitBreaker
注解开启断路器功能:
5、在使用ribbon消费服务的函数上增加@HystrixCommand
注解来指定回调方法。
6、测试(关闭消费者的2个端口,运行Ribbon),结果如下
六、构建Config Server
一、新建一个congfig项目
1、新建一个Config项目工程
2、在pom.xml文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
3、创建一个新的git仓库,并clone到本地
完成后,新建一个config-repo文件夹,文件夹中包含三个环境
//以dev示例
msg=dev
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
不要忘记commit and push
!!!
4、在application.properties中配置服务信息以及git信息,例如:
5、开启配置中心的注解
6、测试路径为:git仓库中的环境名称http://localhost:8085/springsecurity/dev
二、在其他项目要使用配置中心的配置
1、client在pom.xml中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2、创建bootstrap.properties配置,来指定config server,例如:
3、controller层通过@value引用引用文件注入
4、测试路径:http://localhost:8761/add?a=1&b=19
并查看控制台输出:
七、配置服务网关
根据之前对filterType生命周期介绍,可以参考下图去理解,并根据自己的需要在不同的生命周期中去实现不同类型的过滤器。
1、准备工作:
在服务中心启动2个端口,如图
一、开始使用Zuul
1、新建一个工程为Zuul,并在pom.xml文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、应用主类使用@EnableZuulProxy注解开启Zuul
@EnableZuulProxy
@SpringCloudApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3、在application.properties中配置Zuul应用的基础信息,如:应用名、服务端口等。
spring.application.name=Zuul
server.port=8886
二、Zuul配置
1、服务路由,通过服务路由的功能,我们在对外提供服务的时候,只需要通过暴露Zuul中配置的调用地址就可以让调用方统一的来访问我们的服务,而不需要了解具体提供服务的主机信息了。
在Zuul中提供了两种映射方式:
1.1、通过url直接映射,我们可以如下配置:
#这里的配置表示,访问/api-a-url/** 直接重定向到http://localhost:8086/
# routes to url
zuul.routes.api-a-url.path=/api-a-url/**
zuul.routes.api-a-url.url=http://localhost:8086/
该配置,定义了,所有到Zuul的中规则为:/api-a-url/**
的访问都映射到http://localhost:8086/
上,也就是说当我们访问http://localhost:8886/api-a-url/add?a=1&b=2
的时候,Zuul会将该请求路由到:http://localhost:8086/add?a=1&b=2
上。
1.2、将Zuul注册到eureka server上去发现其他服务,我们就可以实现对serviceId的映射。例如,我们可以如下配置:
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=ClientA
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=ClientB
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
在准备工作中实现的两个微服务ClientA和ClientB,定义了两个路由api-a和api-b来分别映射。另外为了让Zuul能发现ClientA和ClientB,也加入了eureka的配置。
可以看到以下图,说明ClientA、ClientB启动成功!
尝试通过服务网关来访问ClientA和ClientB,根据配置的映射关系,分别访问下面的url:
http://localhost:8886/api-a-url/add?a=1&b=87
:通过serviceId映射访问ClientA中的add服务,如下图
http://localhost:5555/api-b/add?a=1&b=2
:通过serviceId映射访问ClientB中的add服务,如下图:
http://localhost:5555/api-a-url/add?a=1&b=2
:通过url映射访问ClientA中的add服务,如下图:
三、服务过滤
在完成了服务路由之后,我们对外开放服务还需要一些安全措施来保护客户端只能访问它应该访问到的资源。所以我们需要利用Zuul的过滤器来实现我们对外服务的安全控制。
在服务网关中定义过滤器只需要继承ZuulFilter抽象类
实现其定义的四个抽象函数就可对请求进行拦截与过滤。
1、比如下面的例子,定义了一个Zuul过滤器,实现了在请求被路由之前检查请求中是否有accessToken参数,若有就进行路由,若没有就拒绝访问,返回401 Unauthorized错误。
@Component
public class AccessFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("accessToken");
if(accessToken == null) {
log.warn("access token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
return null;
}
log.info("access token ok");
return null;
}
}
3、启动后,访问地址:http://localhost:8886/api-a/add?a=1&b=2
返回如下图:
当访问:http://localhost:5555/api-a/add?a=1&b=2&accessToken=token
时,如下图:
八、Eureka Server的高可用
为什么要使用高可用?
如果在服务注册中心中挂了一个服务,从而对后续的操作无影响,会自动在另一个服务中启动
1、在Server中创建集群
2、在服务中心(client)、robbin中依次粘贴服务注册中心的三个集群,运行即可