SpringCloud阶段总结
练习项目环境准备
构建父工程
- 选用的spring-cloud的版本是Hoxton.SR1,springboot的版本是2.2.2.RELEASE,springcloudalibaba的版本是2.1.0.RELEASE
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.18.24</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.spring.boot.starter>1.1.22</druid.spring.boot.starter>
<mybatis.spring.boot.version>2.2.2</mybatis.spring.boot.version>
<spring.boot.dependencies.version>2.2.2.RELEASE</spring.boot.dependencies.version>
<spring.cloud.alibaba.dependencies.version>2.1.0.RELEASE</spring.cloud.alibaba.dependencies.version>
<spring.cloud.dependencies.version>Hoxton.SR1</spring.cloud.dependencies.version>
</properties>
- 在父工程中加入dependencyManagement(依赖管理器),dependencyManagement可以将项目中用到的maven地址进行统一的管理,保证子项目中的maven坐标的版本号一致
- 注意在子项目中仍然需要引入manven坐标
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.spring.boot.starter}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.dependencies.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>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
服务注册
Eureka
使用步骤
- 创建eureka微服务
- 导入eureka maven坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
server:
port: 7001
spring:
application:
name: eureka-service
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server:
enable-self-preservation: true
- 在服务端启动类上添加@EnableEurekaServer注解
- 在微服务添加eureka客户端maven坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://127.0.0.1:7001/eureka/
注意: defaultZone在编写时没有智能提示,当时我在运行项目时,因为字母拼写错误,并且直接复制到另一个微服务项目中,结果两个都无法运行,最后才发现是拼写错误,在此记录一下那段不堪回首的岁月。
- 在启动类上添加@EnableEurekaClient、@EnableDiscoveryClient注解,
第一个注解作用是,启动eureka的客户端,第二个注解时可以获取在eureka中注册的服务信息(在后面的ribbon的使用中会进行描述)
服务调用
- 两种方式,一种是restTemplete+Ribbon实现服务的调用
- 另一种是使用springcloude官方推荐的openfeign进行服务的远程调用
RestTmplete+Ribbon
- 使用方法简单, 在配置类中注入RestTemplete,并且添加**@LoadBalanced**注解
- 使用testtemplete注解进行服务的调用,即将IP地址与端口替换成服务的名称
- 如何被调用服务中是微服务集群,则默认采用轮询算法(Round)
负载均衡
- Ribbon是服务器内的负载均衡,即选择访问哪个微服务项目,Nginx是实现服务器端的负载均衡,决定访问哪个服务器
- 实现负载均衡算法的替换
- 在启动类所在包之外新建配置文件(将配置文件放在@CompentSacn注解扫描不到的包下方),可以实现对特定微服务的定制化算法更换
- 在Myribbonrule配置类中,注入Irule实现类,添加@Configuration注解
@Configuration
public class Myribbonrule {
@Bean
public IRule iRule(){
return new RandomRule();
}
}
- Ribbon内置的负载均衡策略
- 手写Ribbon的轮询算法
- 实现原理:此时请求的次数%该微服务集群的数量=本次请求第几个微服务
@GetMapping("getport")
public R getport() {
String url = "http://PAYMENT-SERVICE/port";
List<ServiceInstance> instancesById = discoveryClient.getInstances("PAYMENT-SERVICE");
ServiceInstance choicceservice = loaeBalance.choicceservice(instancesById);
ResponseEntity<R> forEntity = restTemplate.getForEntity( choicceservice.getUri()+"/port", R.class);
return forEntity.getBody();
}
public interface LoaeBalance {
ServiceInstance choicceservice(List<ServiceInstance> instancesById);
}
@Component
public class LoadBalanceiml implements LoaeBalance {
private AtomicInteger atomicInteger;
public LoadBalanceiml() {
this.atomicInteger = new AtomicInteger(0);
}
int getcurrent(int count) {
int current;
int next;
do {
current = atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!this.atomicInteger.compareAndSet(current, next));
return next;
}
@Override
public ServiceInstance choicceservice(List<ServiceInstance> instancesById) {
if (instancesById==null || instancesById.size()==0){
return null;
}
int count=instancesById.size();
int next = getcurrent(count);
next=next%count;
return instancesById.get(next);
}
}
OpenFeign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 在启动类上添加@EnableFeignClients注解
- 新建feign接口,添加@FeignClient注解,
@FeignClient(value = "PAYMENT-SERVICE",configuration = FeignConfiogure.class)
public interface Feighdao {
@PostMapping
public R addcontroller(@RequestBody Payment payment);
@GetMapping("port")
public R<String> getport();
@GetMapping("{id}")
public R<Payment> getpayment(@PathVariable(value = "id") long id);
注意如何使用@pathvariable注解时,需要将参数名称写入value参数中,@PathVariable(value = “id”) long id否则会报错,血与泪的教训。
public class FeignConfiogure {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
feign:
client:
config:
PAYMENT-SERVICE:
loggerLevel: BASIC
connectTimeout: 2000
readTimeout: 5000
httpclient:
max-connections: 200
max-connections-per-route: 50
- 基于配置文件修改feign的日志级别可以针对单个服务:
feign:
client:
config:
userservice:
loggerLevel: FULL
也可以针对所有服务:
feign:
client:
config:
default:
loggerLevel: FULL
而日志的级别分为四种:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
|