SpringCloud基础学习之搭建项目
1.cloud简介

SpringCloud 是微服务一站式服务解决方案,微服务全家桶。它是微服务开发的主流技术栈。它采用了名称,而非数字版本号。
springCloud 和 springCloud Alibaba 目前是最主流的微服务框架组合。
2.搭建工程
2.1先搭建父工程
配置pom依赖
<!-- 统一管理 jar 包版本 -->
<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>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 下面三个基本是微服务架构的标配 -->
<!--spring boot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud 阿里巴巴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</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>
2.3搭建子工程
步骤1
- 建模块.
- 添加pom依赖
- 写配置文件yml
- 编写启动类
- 业务逻辑
2.3.1服务提供者
1.子模块名称: cloud-provider-parment8001
2.编写pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.编写application.yml
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
username: root
password: 123
url: jdbc:mysql://localhost:3306/test03?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: org.gjt.mm.mysql.Driver
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: org.example.pojo
4.编写启动类
@SpringBootApplication
public class PaymentApplication {
public static void main(String[] args) {
SpringApplication.run(PaymentApplication.class,args);
}
}
5.编写业务逻辑
创建表
CREATE TABLE `payment`(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`serial` VARCHAR(200) DEFAULT '',
PRIMARY KEY(`id`)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8payment
创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
private Long id;
private String serial;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
private Integer code;
private String messgae;
private T data;
/**
* 查询为空的时候使用的构造器
* @param code
* @param messgae
*/
public CommonResult(Integer code, String messgae){
this(code, messgae, null);
}
}
创建dao层
@Mapper
public interface PaymentDao {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
创建mapper映射文件(resources/mapper) PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.kriss.dao.PaymentDao">
<insert id="create" parameterType="payment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial) values (#{serial})
</insert>
<resultMap id="BaseResultMap" type="com.kriss.entity.Payment">
<id column="id" property="id" jdbcType="BIGINT"></id>
<result column="serial" property="serial" jdbcType="VARCHAR"></result>
</resultMap>
<select id="getPaymentById" parameterType="long" resultMap="BaseResultMap">
select * from payment where id=#{id}
</select>
</mapper>
创建service
public interface PaymentService {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
@Service
@SuppressWarnings(value = "all")//压制警告
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentDao paymentDao;
@Override
public int create(Payment payment) {
return paymentDao.create(payment);
}
@Override
public Payment getPaymentById(Long id) {
return paymentDao.getPaymentById(id);
}
}
创建controller
@RestController //必须是这个注解,因为是模拟前后端分离的restful风格的请求,要求每个方法返回 json
@Slf4j
public class PaymentController {
@Autowired
PaymentService paymentService;
@PostMapping(value = "/payment/create")
public CommonResult create(Payment payment){
int result = paymentService.create(payment);
if(result > 0){
return new CommonResult(200, "插入数据库成功", result);
}
return new CommonResult(444, "插入数据库失败", null);
}
@GetMapping(value = "/payment/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("****查询结果:" + payment);
if(payment != null){
return new CommonResult(200, "查询成功", payment);
}
return new CommonResult(444, "没有对应id的记录", null);
}
}
搭建好后的框架

启动测试

2.3.2服务消费者
消费者名称:cloud-consumer-order80
1.导入配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置文件application.yml
server:
port: 80
编写启动类
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
实体类将提供者中的拷贝到消费者即可
注入RestTemplate
我们要用RestTemplate来进行服务调用,所以我们需要在spring容器中注入RestTemplate.
@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
编写controller
@RestController
@Slf4j
public class OrderController {
@Autowired
RestTemplate restTemplate;
//远程调用的 地址
public static final String PAYMENY_URL = "http://localhost:8001";
/**
param1 请求地址,param2 请求参数, param3 返回类型
*/
@PostMapping("consumer/payment/create")
public CommonResult<Payment> create(Payment payment){
return restTemplate.postForObject(PAYMENY_URL+"/payment/create",payment,CommonResult.class);
}
@GetMapping("consumer/payment/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id")Long id){
return restTemplate.getForObject(PAYMENY_URL+"/payment/"+id,CommonResult.class);
}
}

最终效果
测试

3.搭建eureka集群
在你的电脑目录下找到:C:\Windows\System32\drivers\etc\hosts
打开添加
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
继续在父工程创建两个子项目
cloud-eureka-server7001
cloud-eureka-server7002
带入依赖
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.krisswen.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
7001的配置文件
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka 服务器的实例名称 127.0.0.1
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 设置与 Eureka Server 交互的地址,查询服务 和 注册服务都依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
7002配置文件
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka 服务器的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#一定要注意这里的地址,这是搭建集群的关键
defaultZone: http://eureka7001.com:7001/eureka/
要修改提供者配置文件和消费者配置文件
提供者配置
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
username: root
password: 123
url: jdbc:mysql://localhost:3306/test03?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: org.gjt.mm.mysql.Driver
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: org.example.pojo
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001
prefer-ip-address: true
消费者配置
server:
port: 80
spring:
application:
name: cloud-consumer-order80
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
分别启动两台eureka


实现效果如上
4.服务提供方集群搭建
新建子模块名称:
cloud-provider-payment8002
模块里内容直接复制cloud-provider-payment8001即可
需要修改的
1.配置文件中端口号改为8002
启动效果


5.简述eureka的自我保护模式? 如何配置其自我保护模式
1.eureka自我保护介绍
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,这就可能变得非常危险了----因为微服务本身是健康的,此时本不应该注销这个微服务。
Eureka Server通过“自我保护模式”来解决这个问题----当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
自我保护模式是一种对网络异常的安全保护措施。使用自我保护模式,而已让Eureka集群更加的健壮、稳定。
2. 如何配置其自我保护模式
禁止自我保护: 在 Eureka Server 的模块中的 yml 文件进行配置:

修改 Eureka Client 模块的心跳间隔时间:

6.什么是CAP理论? cp ap原则的含义
CAP定理又称CAP原则,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),最多只能同时三个特性中的两个,三者不可兼得。
一、CAP的定义
Consistency (一致性):
“all nodes see the same data at the same time”,即更新操作成功并返回客户端后,所有节点在同一时间的数据完全一致,这就是分布式的一致性。一致性的问题在并发系统中不可避免,对于客户端来说,一致性指的是并发访问时更新过的数据如何获取的问题。从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致。
Availability (可用性):
可用性指“Reads and writes always succeed”,即服务一直可用,而且是正常响应时间。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
Partition Tolerance (分区容错性):
即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体。比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,对于用户而言并没有什么体验上的影响。
二、取舍策略
CAP三个特性只能满足其中两个,那么取舍的策略就共有三种:
CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但放弃P的同时也就意味着放弃了系统的扩展性,也就是分布式节点受限,没办法部署子节点,这是违背分布式系统设计的初衷的。
CP without A:如果不要求A(可用),相当于每个请求都需要在服务器之间保持强一致,而P(分区)会导致同步时间无限延长(也就是等待数据同步完才能正常访问服务),一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。设计成CP的系统其实不少,最典型的就是分布式数据库,如Redis、HBase等。对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。
AP wihtout C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。
7.eureka 和zookeeper consul的区别?
最大的区别是Eureka保证AP, Consul为CP。
Consul强一致性©带来的是:
服务注册相比Eureka会稍慢一些。因为Consul的raft协议要求必须过半数的节点都写入成功才认为注册成功
Leader挂掉时,重新选举期间整个consul不可用。保证了强一致性但牺牲了可用性。
Eureka保证高可用(A)和最终一致性:
服务注册相对要快,因为不需要等注册信息replicate到其他节点,也不保证注册信息是否replicate成功
当数据出现不一致时,虽然A, B上的注册信息不完全相同,但每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如此保证了可用性但牺牲了一致性。
8.使用ribbon进行负载均衡的步骤
1.引入依赖
spring-cloud-starter-netflix-eureka-client
2.在服务消费方开启负载均衡

3.测试负载均衡
在8001和8002服务分别添加:

测试结果是轮循的方式来进行的
9.ribbon负载均衡的策略有哪些?

10.如何自定义负载均衡
1.首先在消费者里面在启动类的上一级定义配置文件
package org.myconfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RibbonConfig {
@Bean
public IRule iRule(){
//自定义负载均衡的策略 随机
return new RandomRule();
}
}
然后在启动类上加
@RibbonClient(name = “cloud-payment-service”,configuration = RibbonConfig.class)
注解即可
上述一例单可以实现多种不同的自定义负载均衡。

搞起来!
本文详细介绍SpringCloud微服务架构的基础搭建过程,包括工程结构、Eureka集群配置、服务提供者与消费者的实现,以及Eureka自我保护模式的配置方法。同时探讨了CAP理论,并对比了Eureka、Zookeeper和Consul的特点。
5万+

被折叠的 条评论
为什么被折叠?



