不论是商业应用还是用户应用,在业务初期都很简单,我们通常会把它实现为单体结构的应用。但是,随着业务逐渐发展,产品思想会变得越来越复杂,单体结构的应用也会越来越复杂。这就会给应用带来如下的几个问题:
由于单体结构的应用随着系统复杂度的增高,会暴露出各种各样的问题。近些年来,微服务架构逐渐取代了单体架构,且这种趋势将会越来越流行。Spring Cloud是目前最常用的微服务开发框架,已经在企业级开发中大量的应用。
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
协调各个微服务,简化分布式系统开发。
微服务的框架那么多比如:dubbo、Kubernetes,为什么就要使用Spring Cloud的呢?
优点:
缺点:
总的来说优点大过于缺点,目前看来Spring Cloud是一套非常完善的分布式框架,目前很多企业开始用微服务、Spring Cloud的优势是显而易见的。因此对于想研究微服务架构的同学来说,学习Spring Cloud是一个不错的选择。
Spring Cloud对于中小型互联网公司来说是一种福音,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用Spring Cloud一站式解决方案能在从容应对业务发展的同时大大减少开发成本。同时,随着近几年微服务架构和Docker容器概念的火爆,也会让Spring Cloud在未来越来越“云”化的软件开发风格中立有一席之地,尤其是在五花八门的分布式解决方案中提供了标准化的、全站式的技术方案,意义可能会堪比当年Servlet规范的诞生,有效推进服务端软件系统技术水平的进步。
Spring Cloud的子项目,大致可分成两类,
一类是对现有成熟框架"Spring Boot化"的封装和抽象,也是数量最多的项目;
第二类是开发了一部分分布式系统的基础设施的实现,如Spring Cloud Stream扮演的就是kafka, ActiveMQ这样的角色。
集中配置管理工具,分布式系统中统一的外部配置管理,默认使用Git来存储配置,可以支持客户端配置的刷新及加密、解密操作。
Netflix OSS 开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心组件。
用于传播集群状态变化的消息总线,使用轻量级消息代理链接分布式系统中的节点,可以用来动态刷新集群中的服务配置。
基于Hashicorp Consul的服务治理组件。
安全工具包,对Zuul代理中的负载均衡OAuth2客户端及登录认证进行支持。
Spring Cloud应用程序的分布式请求链路跟踪,支持使用Zipkin、HTrace和基于日志(例如ELK)的跟踪。
轻量级事件驱动微服务框架,可以使用简单的声明式模型来发送及接收消息,主要实现为Apache Kafka及RabbitMQ。
用于快速构建短暂、有限数据处理任务的微服务框架,用于向应用中添加功能性和非功能性的特性。
基于Apache Zookeeper的服务治理组件。
API网关组件,对请求提供路由及过滤功能。
基于Ribbon和Hystrix的声明式服务调用组件,可以动态创建基于Spring MVC注解的接口实现用于服务调用,在Spring Cloud 2.0中已经取代Feign成为了一等公民。
Spring Cloud是一个由许多子项目组成的综合项目,各子项目有不同的发布节奏。 为了管理Spring Cloud与各子项目的版本依赖关系,发布了一个清单,其中包括了某个Spring Cloud版本对应的子项目版本。 为了避免Spring Cloud版本号与子项目版本号混淆,Spring Cloud版本采用了名称而非版本号的命名,这些版本的名字采用了伦敦地铁站的名字,根据字母表的顺序来对应版本时间顺序,例如Angel是第一个版本,Brixton是第二个版本。 当Spring Cloud的发布内容积累到临界点或者一个重大BUG被解决后,会发布一个"service releases"版本,简称SRX版本,比如Greenwich.SR2就是Spring Cloud发布的Greenwich版本的第2个SRX版本。目前Spring Cloud的最新版本是Hoxton。
注意:Hoxton版本是基于SpringBoot 2.2.x版本构建的,不适用于1.5.x版本。随着2019年8月SpringBoot 1.5.x版本停止维护,Edgware版本也将停止维护。
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
(1)与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。
(2)服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。
(3)冗余-分布式系统中的冗余问题。
(4)负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,中央处理单元,或磁盘驱动器的分布。
(5)性能-问题 由于各种运营开销导致的性能问题。
(6)部署复杂性-Devops 技能的要求。
当我们开始一个项目时,我们通常在属性文件中进行所有的配置。随着越来越多的服务开发和部署,添加和修改这些属性变得更加复杂。有些服务可能会下降,而某些位置可能会发生变化。手动更改属性可能会产生问题。 Eureka 服务注册和发现可以在这种情况下提供帮助。由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找,因此无需处理服务地点的任何更改和处理。
(1)服务调用方式 dubbo是RPC springcloud Rest Api
(2)注册中心,dubbo 是zookeeper springcloud是eureka,也可以是zookeeper
(3)服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。
在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。
Hystrix 是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。
通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。
思考以下微服务
假设如果上图中的微服务 9 失败了,那么使用传统方法我们将传播一个异常。但这仍然会导致整个系统崩溃。
随着微服务数量的增加,这个问题变得更加复杂。微服务的数量可以高达 1000.这是 hystrix 出现的地方 我们将使用 Hystrix 在这种情况下的 Fallback 方法功能。我们有两个服务 employee-consumer 使用由 employee-consumer 公开的服务。
现在假设由于某种原因,employee-producer 公开的服务会抛出异常。我们在这种情况下使用 Hystrix 定义了一个回退方法。这种后备方法应该具有与公开服务相同的返回类型。如果暴露服务中出现异常,则回退方法将返回一些值。
由于某些原因,employee-consumer 公开服务会引发异常。在这种情况下使用Hystrix 我们定义了一个回退方法。如果在公开服务中发生异常,则回退方法返回一些默认值。
如果 firstPage method() 中的异常继续发生,则 Hystrix 电路将中断,并且员工使用者将一起跳过 firtsPage 方法,并直接调用回退方法。 断路器的目的是给第一页方法或第一页方法可能调用的其他方法留出时间,并导致异常恢复。可能发生的情况是,在负载较小的情况下,导致异常的问题有更好的恢复机会 。
Feign 是受到 Retrofit,JAXRS-2.0 和 WebSocket 启发的 java 客户端联编程序。
Feign 的第一个目标是将约束分母的复杂性统一到 http apis,而不考虑其稳定性。
在 employee-consumer 的例子中,我们使用了 employee-producer 使用 REST模板公开的 REST 服务。
但是我们必须编写大量代码才能执行以下步骤
(1)使用功能区进行负载平衡。
(2)获取服务实例,然后获取基本 URL。
(3)利用 REST 模板来使用服务。 前面的代码如下
@Controller
public class ConsumerControllerClient {
@Autowired
private LoadBalancerClient loadBalancer;
public void getEmployee() throws RestClientException, IOException {
ServiceInstance serviceInstance=loadBalancer.choose("employee-producer");
System.out.println(serviceInstance.getUri());
String baseUrl=serviceInstance.getUri().toString();
baseUrl=baseUrl+"/employee";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response=null;
try{
response=restTemplate.exchange(baseUrl,
HttpMethod.GET, getHeaders(),String.class);
}
catch (Exception ex)
{
System.out.println(ex);
}
System.out.println(response.getBody());
}
之前的代码,有像 NullPointer 这样的例外的机会,并不是最优的。我们将看到如何使用 Netflix Feign 使呼叫变得更加轻松和清洁。如果 Netflix Ribbon 依赖关系也在类路径中,那么 Feign 默认也会负责负载平衡。
考虑以下情况:我们有多个应用程序使用 Spring Cloud Config 读取属性,而Spring Cloud Config 从 GIT 读取这些属性。
下面的例子中多个员工生产者模块从 Employee Config Module 获取 Eureka 注册的财产
如果假设 GIT 中的 Eureka 注册属性更改为指向另一台 Eureka 服务器,会发生什么情况。在这种情况下,我们将不得不重新启动服务以获取更新的属性。
还有另一种使用执行器端点/刷新的方式。但是我们将不得不为每个模块单独调用这个 url。例如,如果 Employee Producer1 部署在端口 8080 上,则调用 http:// localhost:8080 / refresh。同样对于 Employee Producer2 http://localhost:8081 / refresh 等等。这又很麻烦。这就是 Spring Cloud Bus 发挥作用的地方。
Spring Cloud Bus 提供了跨多个实例刷新配置的功能。因此,在上面的示例中,如果我们刷新 Employee Producer1,则会自动刷新所有其他必需的模块。如果我们有多个微服务启动并运行,这特别有用。这是通过将所有微服务连接到单个消息代理来实现的。无论何时刷新实例,此事件都会订阅到侦听此代理的所有微服务,并且它们也会刷新。可以通过使用端点/总线/刷新来实现对任何单个实例的刷新。
当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应 当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)
断路器有完全打开状态:一段时间内 达到一定的次数无法调用 并且多次监测没有恢复的迹象 断路器完全打开 那么下次请求就不会请求到该服务
半开:短时间内 有恢复迹象 断路器会将部分请求发给该服务,正常调用时 断路器关闭
关闭:当服务一直处于正常状态 能正常调用
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
使用:
(1)添加pom依赖
(2)配置文件添加相关配置
(3)启动类添加注解@EnableConfigServer
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。
使用了一个RouteLocatorBuilder的bean去创建路由,除了创建路由RouteLocatorBuilder可以让你添加各种predicates和filters,predicates断言的意思,顾名思义就是根据具体的请求的规则,由具体的route去处理,filters是各种过滤器,用来对请求做各种判断和修改。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kxj6lx4M-1673798095503)(…/…/…/typora/image/image-20210307151250922.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEnD5dYT-1673798095504)(…/…/…/typora/image/image-20210307151301797.png)]
springcloud=分布式微服务框架的一站式解决方案,是多种微服务框架落地技术的集合体,俗称微服务全家桶
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYQDcEOh-1673798095504)(…/…/…/typora/image/image-20210307151511028.png)]
springcloud和springboot版本配对
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-giX0sa2A-1673798095505)(…/…/…/typora/image/image-20210307151617268.png)]
本次学习使用版本
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qW8rRipM-1673798095506)(…/…/…/typora/image/image-20210307151635716.png)]
改变编码为UTF-8
设置注释功能开启
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSaG2QOL-1673798095507)(…/…/…/typora/image/image-20210307151714447.png)]
过滤不必要的文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0cpm3d8-1673798095508)(…/…/…/typora/image/image-20210307151736786.png)]
删光光只留下pom文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4enh9I6-1673798095508)(…/…/…/typora/image/image-20210307151755817.png)]
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<junit.version>4.12junit.version>
<log4j.version>1.2.17log4j.version>
<lombok.version>1.16.18lombok.version>
<mysql.version>5.1.47mysql.version>
<druid.version>1.1.16druid.version>
<mybatis.spring.boot.version>1.3.0mybatis.spring.boot.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR1version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis.spring.boot.version}version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
<optional>trueoptional>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
<addResources>trueaddResources>
configuration>
plugin>
plugins>
build>
dependencyManagement:
通常会在一个组织或项目的最顶层的父pom中看到dependencyManagement元素。
子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXoCH4To-1673798095509)(…/…/…/typora/image/image-20210307152125807.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-frsLVLbO-1673798095510)(…/…/…/typora/image/image-20210307152233994.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kvndWUnu-1673798095510)(…/…/…/typora/image/image-20210307152423339.png)]
pom.xml
<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">
<parent>
<artifactId>com.luyi.cloudartifactId>
<groupId>com.luyi.cloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-provider-payment8001artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
dependencies>
project>
package com.luyi.cloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author 卢意
* @create 2020-10-20 10:21
*/
@Data
@AllArgsConstructor // 有参构造函数
@NoArgsConstructor //无参函数
public class Payment implements Serializable { //为对象提供标准的序列化与反序列化操作
private Long id;
/**
* 订单号
*/
private String serial;
}
package com.luyi.cloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 卢意
* @create 2020-10-20 10:30
*/
@Data //lombok 自动生成getset
@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);
}
}
package com.luyi.cloud.dao;
import com.luyi.cloud.entity.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @author 卢意
* @create 2020-10-20 10:35
*/
@Mapper
public interface PaymentDao {
public int create(Payment payment);
public int getPaymentById(@Param("id") Long id);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.cloud.dao.PaymentDao">
<insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
insert into payment values (#{serial});
insert>
<resultMap id="BaseResultMap" type="com.luyi.cloud.entity.Payment">
<id column="id" property="id" javaType="BIGINT" />
<id column="serial" property="serial" javaType="VARCHAR" />
resultMap>
<select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
select * from payment where id=#{id}
select>
mapper>
package com.luyi.cloud.service.impl;
import com.luyi.cloud.dao.PaymentDao;
import com.luyi.cloud.entity.Payment;
import com.luyi.cloud.service.PaymentService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-10-20 10:53
*/
@Service("paymentService")
public class PaymentServiceImpl implements PaymentService {
@Resource
private PaymentDao paymentDao;
@Override
public int create(Payment payment) {
return paymentDao.create(payment);
}
@Override
public int getPaymentById(Long id) {
return paymentDao.getPaymentById(id);
}
}
package com.luyi.payment.controller;
import com.luyi.payment.entity.CommonResult;
import com.luyi.payment.entity.Payment;
import com.luyi.payment.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-10-20 10:58
*/
@Controller
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
// @RequestMapping("/")
// public CommonResult index(Payment payment){
// System.out.println(12);
// return new CommonResult(200,"插入数据库成功","test");
// }
@Resource
private PaymentService paymentService;
@PostMapping(value = "/create")
public CommonResult create(Payment payment){
Integer result=paymentService.create(payment);
log.info("****插入结果:"+result);
if (result<0){
return new CommonResult(200,"插入数据库成功",result);
}else {
return new CommonResult(444,"插入数据库失败",null);
}
}
//通过id进行查询
@GetMapping("/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id ){
Payment payment=paymentService.getPaymentById(id);
log.info("****插入结果:"+payment);
if (payment!=null){
return new CommonResult(200,"查询成功",payment);
}else {
return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
}
}
}
知识点
@GetMapping
用于将HTTP GET请求映射到特定处理程序方法的注释。具体来说,@GetMapping是一个作为快捷方式的组合注释
@RequestMapping(method = RequestMethod.GET)。
@PostMapping
用于将HTTP POST请求映射到特定处理程序方法的注释。具体来说,@PostMapping是一个作为快捷方式的组合注释@RequestMapping(method = RequestMethod.POST)。
@RequestMapping:
一般情况下都是用@RequestMapping(method=RequestMethod.),因为@RequestMapping可以直接替代以上两个注解,但是以上两个注解并不能替代@RequestMapping,@RequestMapping相当于以上两个注解的父类!
类似的组合注解还有:
@PutMapping、@DeleteMapping、@PatchMapping
总结下来就是@PostMapping和@GetMapping都可以用@RequestMapping代替,如果读者怕在映射的时候出错,可以统一写@RequestMapping,当然这样写的话也有弊端,笼统的全用@RequestMapping, 不便于其他人对代码的阅读和理解!还是建议区分开来写!养成良好的代码习惯!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T0bD8d8O-1673798095511)(…/…/…/typora/image/image-20210307154610494.png)]
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
<addResources>trueaddResources>
configuration>
plugin>
plugins>
build>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YqWMSsKN-1673798095512)(…/…/…/typora/image/image-20210307154738576.png)]
ctrl + shift +Alt +/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwwffMXk-1673798095513)(…/…/…/typora/image/image-20210307162703844.png)]
重启IDEA
com.luyi.cloud
com.luyi.cloud
1.0-SNAPSHOT
4.0.0
cloud-consuner-order80
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
com.alibaba
druid
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.3
org.mybatis
mybatis
3.5.5
org.springframework.boot
spring-boot-autoconfigure
2.2.2.RELEASE
server:
port: 80
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DIHVsmcT-1673798095514)(…/…/…/typora/image/image-20210307162817964.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Irsa0RIs-1673798095515)(…/…/…/typora/image/image-20210307162834267.png)]
package com.luyi.order.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* 上下文配置类
* @author 卢意
* @create 2020-10-20 20:42
*/
@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
package com.luyi.payment.controller;
import com.luyi.payment.entity.CommonResult;
import com.luyi.payment.entity.Payment;
import com.luyi.payment.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-10-20 10:58
*/
@RestController
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
// @RequestMapping("/")
// public CommonResult index(Payment payment){
// System.out.println(12);
// return new CommonResult(200,"插入数据库成功","test");
// }
@Resource
private PaymentService paymentService;
@PostMapping(value = "/create")
public CommonResult create(Payment payment){
Integer result=paymentService.create(payment);
log.info("****插入结果:"+result);
if (result<0){
return new CommonResult(200,"插入数据库成功",result);
}else {
return new CommonResult(444,"插入数据库失败",null);
}
}
//通过id进行查询
@GetMapping("/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id ){
Payment payment=paymentService.getPaymentById(id);
log.info("****插入结果:"+payment);
if (payment!=null){
return new CommonResult(200,"查询成功",payment);
}else {
return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
}
}
}
通过order 模块调用payment模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MY0eufjy-1673798095515)(…/…/…/typora/image/image-20210307163328507.png)]
把公用代码写在一个模块里
<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">
<parent>
<artifactId>com.luyi.cloudartifactId>
<groupId>com.luyi.cloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-api-commonsartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.1.0version>
dependency>
dependencies>
project>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hFUcMQvg-1673798095516)(…/…/…/typora/image/image-20210307163536858.png)]
<dependency>
<groupId>com.luyi.cloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>${project.version}version>
dependency>
然后有些地方改一改
ok了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pez9Wjdz-1673798095517)(…/…/…/typora/image/image-20210307163717202.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cj7Xz0qJ-1673798095517)(…/…/…/typora/image/image-20210307163731585.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZYfD43oH-1673798095518)(…/…/…/typora/image/image-20210307163751379.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rTshGezz-1673798095519)(…/…/…/typora/image/image-20210307163837234.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67Zy0gJ9-1673798095519)(…/…/…/typora/image/image-20210307163918042.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YoH5fTVj-1673798095520)(…/…/…/typora/image/image-20210307164105412.png)]
<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">
<parent>
<artifactId>com.luyi.cloudartifactId>
<groupId>com.luyi.cloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-eureka-server7001artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>com.luyi.cloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
dependencies>
project>
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka 服务器的实例名称
client:
# false 表示不向注册中心注册自己
register-with-eureka: false
# false 表示自己端就是注册中心,我的职责是服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置于Eureka Server交互的地址查询服务和注册服务都涂药和这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
package com.luyi.cloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author 卢意
* @create 2020-10-21 9:25
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
启动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZkLaC3eF-1673798095521)(…/…/…/typora/image/image-20210307164518988.png)]
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
加入
eureka:
client:
#表示是否将自己注册EurekaServer 默认为true
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
@EnableEurekaClient
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKUKjvy1-1673798095522)(…/…/…/typora/image/image-20210307164838033.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXvPVaCa-1673798095522)(…/…/…/typora/image/image-20210307165009264.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGEZ4C0T-1673798095523)(…/…/…/typora/image/image-20210307165047700.png)]
步骤同上
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8kMneN7q-1673798095523)(…/…/…/typora/image/image-20210307165108410.png)]
实现了下图的单机架构设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDZB46Ih-1673798095524)(…/…/…/typora/image/image-20210307165412686.png)]
测试成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G52PpQOq-1673798095524)(…/…/…/typora/image/image-20210307165706024.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfW6ntwz-1673798095525)(…/…/…/typora/image/image-20210307165801467.png)]
高可用 如果一个注册中心,如果故障了就导致整个服务环境不可用
所以搭建Eureka注册中心集群,实现负载均衡+故障容错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dp8TNkaB-1673798095525)(…/…/…/typora/image/image-20210307165818786.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJQeuVgl-1673798095526)(…/…/…/typora/image/image-20210307170137737.png)]
添加进去
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
7001
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka 服务器的实例名称
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:
#设置于Eureka Server交互的地址查询服务和注册服务都涂药和这个地址
defaultZone: http://eureka7001.com:7001/eureka/
相互注册成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xNIYpzIA-1673798095526)(…/…/…/typora/image/image-20210307170700591.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P3Vfgie7-1673798095527)(…/…/…/typora/image/image-20210307170710434.png)]
pom加入注册地址
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/dbspringcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
eureka:
client:
#表示是否将自己注册EurekaServer 默认为true
register-with-eureka: true
fetchRegistry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/erueka # 入驻地址
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.luyi.api.payment.entity # 所有Entity别名类所在包
pom加入注册地址
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
#表示是否将自己注册EurekaServer 默认为true
register-with-eureka: true
fetchRegistry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/erueka # 入驻地址
https://blog.51cto.com/u_14693305/4767831