请注意,本文编写于 2466 天前,最后修改于 640 天前,其中某些信息可能已经过时。
SpringCloud 学习笔记 01 --eureka
1. 新建maven父工程
父工程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>
<!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version -->
<dependencyManagement>
<dependencies>
<!--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 alibaba 2.1.0.RELEASE-->
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<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>
<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>
</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. eureka服务端子模块
a. pom 依赖
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>org.mc.mycloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot web actuator-->
<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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
b. application.yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eruka服务端实例
client:
register-with-eureka: false #false代表不让注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护服务实例,不需要检索服务
service-url:
#设置与eureka server 交互的地址查询服务和注册服务依赖地址
#单机注册自己 集群注册自己以外的所有
#单机:
#defaultZone: http://eureka7001.com:7001/eureka/
#集群
defaultZone: http://eureka7002.com:7002/eureka/
server:
#关闭自我保护机制 保证不可用服务被及时剔除
enable-self-preservation: false
#2秒后删除不可以用服务 默认90秒
eviction-interval-timer-in-ms: 2000
c. 主启动
@SpringBootApplication
@EnableEurekaServer //启用eureka服务器注解
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
3. 服务提供者子模块
a. pom 依赖
<dependencies>
<!--包含了sleuth+zipkin-->
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>-->
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>org.mc.mycloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</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>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>
<dependency>
<groupId>org.mc.mycloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
b. application.yml
server:
port: 8001 #端口号
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: aion
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: org.mc.mycloud.entities # 所有Entity别名类所在包
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
# defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
# 集群:高可用,轮询模式
#主机名称 服务修改
instance:
instance-id: payment8001
# #访问路径可以显示IP地址
prefer-ip-address: true
# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
c. 主启动
@SpringBootApplication
@EnableEurekaClient //启动eureka客户端注解
@EnableDiscoveryClient //启用客户端发现
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
d. 实体类
@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 message;
private T data;
public CommonResult(Integer code,String message)
{
this(code,message,null);
}
}
e. 流程代码
dao:
@Mapper
public interface PaymentDao
{
public int creat(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
xml:
<mapper namespace="org.mc.mycloud.dao.PaymentDao">
<insert id="creat" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial) values(#{serial})
</insert>
<resultMap id="BaseResultMap" type="org.mc.mycloud.entities.Payment">
<id column="id" property="id" jdbcType="BIGINT"/>
<id column="serial" property="serial" jdbcType="VARCHAR"/>
</resultMap>
<select id="getPaymentById" parameterType="long" resultMap="BaseResultMap">
select * from payment where id =#{id}
</select>
</mapper>
service:
public interface PaymentService
{
public int creat(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
@Service
public class PaymentServiceImpl implements PaymentService {
@Resource
private PaymentDao paymentDao;
@Override
public int creat(Payment payment) {
return paymentDao.creat(payment);
}
@Override
public Payment getPaymentById(Long id) {
return paymentDao.getPaymentById(id);
}
}
controller:
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
/* @Resource
private DiscoveryClient discoveryClient;*/
@PostMapping(value = "/payment/creat")
public CommonResult creat(@RequestBody Payment payment) {
int result = paymentService.creat(payment);
log.info("*****插入结果:" + result);
if (result > 0) {
return new CommonResult(200, "插入数据库成功, serverPort:" + serverPort, result);
} else {
return new CommonResult(444, "插入数据库失败, serverPort:" + serverPort, null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id) {
Payment payment = paymentService.getPaymentById(id);
log.info("*****查询结果:" + payment);
if (payment != null) {
return new CommonResult(200, "查询数据库成功, serverPort:" + serverPort, payment);
} else {
return new CommonResult(444, "查询数据库失败, serverPort:" + serverPort + " id:" + id, null);
}
}
/* @GetMapping("/payment/discovery")
public Object discovery() {
//得到服务清单列表
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("*****service:"+service);
}
//根据服务名称获得服务信息实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return this.discoveryClient;
}*/
}
f. 结果
{
"code": 200,
"message": "查询数据库成功, serverPort:8001",
"data": {
"id": 1,
"serial": "payment支付8001"
}
}
4. 消费者子模块
a. pom依赖
<dependencies>
<!-- <!–包含了sleuth+zipkin–>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>org.mc.mycloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</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.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>
b. appliaction.yml
server:
port: 80
spring:
application:
name: cloud-consumer-order
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#主机名称 服务修改
instance:
instance-id: order80
#访问路径可以显示IP地址
prefer-ip-address: true
# #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
# #lease-renewal-interval-in-seconds: 1
# #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
# #lease-expiration-duration-in-seconds: 2
c. 主启动
@SpringBootApplication
@EnableEurekaClient //作为eureka 客户端
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
d. 开启负载均衡
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
e. 流程代码
@RestController
@Slf4j
public class OrderController {
// public static final String PAYMENT_URL = "http://localhost:8001";
//使用服务提供实例名称来实现集群时对服务提供者的选择
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
@PostMapping("/consumer/payment/creat")
public CommonResult<Payment> creat(Payment payment) {
log.info("****消费者数据库插入:80");
return restTemplate.postForObject(PAYMENT_URL + "/payment/creat", payment, CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
log.info("****消费者数据库查询:80 哈哈哈 id:"+id);
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
}
/**/
}
f. 结果
{
"code": 200,
"message": "查询数据库成功, serverPort:8001",
"data": {
"id": 1,
"serial": "payment支付8001"
}
}
5. 总结
a. 客户端集群访问机制?
轮循
b. 为何集群?
高可用 避免宕机造成服务不可用 提高容错
c. 服务端和客服端注解:
@EnableEurekaServer //服务端
@EnableEurekaClient //客户端
d. 开启负载均衡:
@LoadBalanced注解
@LoadBalanced //开启负载均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
e. 集群时消费者端配置地址为:
服务提供者实例名称
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
f. eureka服务端yml
eureka:
instance:
hostname: eureka7001.com #eruka服务端实例
client:
register-with-eureka: false #false代表不让注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护服务实例,不需要检索服务
service-url:
#设置与eureka server 交互的地址查询服务和注册服务依赖地址
#单机注册自己 集群注册自己以外的所有
#单机:
#defaultZone: http://eureka7001.com:7001/eureka/
#集群
defaultZone: http://eureka7002.com:7002/eureka/
server:
#关闭自我保护机制 保证不可用服务被及时剔除
enable-self-preservation: false
#2秒后删除不可以用服务 默认90秒
eviction-interval-timer-in-ms: 2000
g. eureka客户端yml
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
# defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#主机名称 服务修改
instance:
instance-id: payment8001
# #访问路径可以显示IP地址
prefer-ip-address: true
# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
h. 服务端自我保护机制关闭
enable-self-preservation: false
i. 服务发现注解
主启动添加
@EnableDiscoveryClient //服务发现注解
j: 服务端集群方式:
互相注册
#单机注册自己:
#defaultZone: http://eureka7001.com:7001/eureka/
#集群注册其他
defaultZone: http://eureka7002.com:7002/eureka/