文章目录
注: 大概写个笔记记录一下
一、springcloud简单介绍
二、Eureka
也可以使用consul / zookeeper作为资源注册器
vs
- spring boot 2.0 推荐使用eureka服务端的
<!--Eureka注册其服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
- 废弃的 jar
<!--Eureka注册其服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
1、使用纯maven创建一个简单的springcloud项目
2、编写父级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.lc</groupId>
<artifactId>springcloudEurekaNew</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-api</module>
</modules>
<!--打包方式-->
<packaging>pom</packaging>
<!--依赖版本控制-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
<spring-boot.version>2.1.13.RELEASE</spring-boot.version>
<lombok.version>1.18.8</lombok.version>
<druid.version>1.1.8</druid.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<dependencyManagement>
<dependencies>
<!--springloud 依赖继承-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springboot的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--引入阿里 druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--引入mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--引入mybatis驱动-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--lombok依赖引入-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--测试包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3idea懒人创建注册器
4.手动创建maven再导包(便于管理)
5.provider 懒人创建模式
服务者:application.yml中的
#spring配置
spring:
application:
name: springcloud-provider-dept_1-0-0 #对应着erueka的Application的名字
#Eureka的配置,服务注册到哪里
eureka:
instance:
instance-id: springcloud-provider-dept8001 #修改eureka默认描述信息就是status
对应者
三、Ribbon 负载均衡
Ribbon属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
新版本springCloud中Eureka集成了Ribbon的包
<!--eureka-client Ribbon也是这个包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1.Ribbon集成
package com.common.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
//负载均衡实现RestTemplate
@Bean
@LoadBalanced //Reibbon
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
2.Ribbon负载均衡规则更换
- 规则
Ribbon负载均衡
1.IRule:根据特定算法中从服务列表中选取一个要访问的服务
RoundRobinRule 轮询 (默认规则)
RandomRule随机
AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务, 还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。 刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够, 会切换到WeightedResponseTimeRule
RetryRule先按照RoundRobinRule 的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器
package com.atguigu.myrule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Configuration
public class MySelfRule
{
@Bean
public IRule myRule()
{
return new RandomRule();//Ribbon默认是轮询,我自定义为随机
}
}
- 修改启动类即可
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
3.自定义复杂的负载均衡算法
- 定义规则
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class RandomRule_ZY extends AbstractLoadBalancerRule {
private int total = 0; //总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0;//当前提供服务的机器号
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
// int index = rand.nextInt(serverCount);
// server = upList.get(index);
if(total < 5)
{
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex++;
if(currentIndex >= upList.size())
{
currentIndex = 0;
}
}
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
- 替换规则
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Configuration
public class MySelfRule
{
@Bean
public IRule myRule()
{
return new RandomRule_ZY();//我自定义为每个机器被访问5次
}
}
- 修改启动类即可
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
- 注意事项
官方文档明确给出了警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说
我们达不到特殊化定制的目的了。
四、Feign
调用微服务的两种方式
1)ribbon + restTemplate
2) feign
Feign将多个消费端restTemplate的工作集中进行了处理;性能变低了奥,可读性提升了
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
Feign是一个声明式的Web服务客户端,使得编写Web服务客户端变得非常容易,只需要创建一个接口,然后在上面添加注解即可。
Feign能干什么
Feign旨在使编写Java Http客户端变得更容易。
前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
- Feign集成了Ribbon
利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
1.@FeignCLient属性介绍
-
value, name
value和name的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。 -
serviceId
serviceId已经废弃了,直接使用name即可。 -
contextId
比如我们有个user服务,但user服务中有很多个接口,我们不想将所有的调用接口都定义在一个类中,比如:
2.使用
- 依赖
<!--feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.DeptClientServer接口提供
package com.lc.springcloud.service;
import com.lc.springcloud.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT") // 使用feign时才用的
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
Dept getById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
List<Dept> getAll();
@PostMapping("/dept/add")
boolean addDept(Dept dept);
}
- 消费端调用
package com.lc.springcloud.controller;
import com.lc.springcloud.pojo.Dept;
import com.lc.springcloud.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService deptClientService;
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return deptClientService.getById(id);
}
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept) {
return deptClientService.addDept(dept);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list() {
return deptClientService.getAll();
}
}
package com.lc.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 1、在Spring Cloud的Dalston及其之前的版本中:
* @Target(ElementType.TYPE)
* @Retention(RetentionPolicy.RUNTIME)
* @Documented
* @Inherited
* @EnableDiscoveryClient
* public @interface EnableEurekaClient { }
*
* 1) 从2014年的Spring Cloud 1.0.0.RC1版本开始,官方就推荐使用EnableDiscoveryClient来取代EnableEurekaClient;
* 2) EnableEurekaClient源码中使用了注解EnableDiscoveryClient,因此如果要使用eureka的注册发现服务,两者功能是一样的;
* 3) EnableDiscoveryClient注解在spring.factories配置中通过配置项EurekaDiscoveryClientConfiguration来开启服务注册发现功能;
*
* 在Spring Cloud的Dalston及其之前的版本中:
* 1. 在spring.factories配置中,配置类EurekaDiscoveryClientConfiguration被配置到springboot的自动配置注解中,
* 与EnableDiscoveryClient注解没有关系了,也就是说只要开启了springboot的自动配置,服务注册发现功能就会启用;
* 2. EnableEurekaClient源码中没有使用注解EnableDiscoveryClient,此时EnableEurekaClient已经没用了;
* 原文链接:https://blog.csdn.net/boling_cavalry/article/details/82668480
*/
@EnableEurekaClient //在服务启动之后自动注册到eureka中
@EnableFeignClients(basePackages = {"com.lc.springcloud"}) // 貌似可以不写包
@SpringBootApplication
public class FeignDeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_80.class, args);
}
}
通过Feign直接找到服务接口,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡作用。