Spring Cloud 学习笔记:微服务

前言

以下内容是我在学习周阳老师的2020最新版 Spring Cloud(H版&alibaba)时的笔记,其中并整合了之前学习G版时的相关笔记。如有错误请指正,谢谢。

大纲

在这里插入图片描述

Spring Cloud

从最原始的开发开始,全部代码都放在一个 .java 文件下,到后来分三层架构 MVC 开发;再后来为了简化不同架构里面的开发从而有了框架:Spring、Spring MVC、Mybatis;再后来 Spring Boot 作为新一代的 Java EE 开发标准,有自动装配、开箱即用的优点。但是模块化的开发本质上还是 all in one 的开发。
微服务因此而出现,微服务提倡将单一的应用程序划分成一组小的服务每个服务运行在其独立的自己的进程中服务之间互相协调互相配置,为用户提供最终价值。微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地解耦,每个微服务提供单个业务功能地服务,一个服务做一件事情,从技术角度看就是一种小而独立地处理过程,类似进程的概念,能够自行单独启动或销毁,拥有独立地数据库。服务与服务间采用轻量级的通信机制互相协作(通常是基于 HTTP 协议的 RESTful API)。
但是微服务的架构有四个核心问题:

服务很多的情况下客户端该怎么访问?
服务与服务之间该如何通信?
服务应该如何治理?
服务挂了该怎么办?

而 Spring Cloud 是一站式解决方案,解决微服务架构里面的四个核心问题,为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性token,全局琐,leader选举,分布式session,集群状态)中快速构建的工具,使用Spring Cloud的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。在这里插入图片描述

父项目:cloud2020

pom.xml
<packaging>pom</packaging>
  <!-- packaging pom 总工程-->
  <!--统一管理jar包版本-->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>12</maven.compiler.source>
    <maven.compiler.target>12</maven.compiler.target>
    <junit.version>4.12</junit.version>
    <lombok.version>1.18.10</lombok.version>
    <log4j.version>1.2.17</log4j.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>

  <!--子模块继承之后,提供作用:锁定版本+子module不用写groupId和version-->
  <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>
    <!--mybatis-->
    <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>
dependencyManagement & dependencies

在这里插入图片描述在这里插入图片描述
这样做的好处就是:如果有多个子项目都引用同一样的依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样想升级或切换到另一个版本时,只需在顶层父容器里更新,而不需要一个一个子项目的修改l;另外如果某个子项目需要另外的一个版本,只需声明version版本。dependencyManagement 里只是声明依赖并不实现引入,因此子项目需要显示的声明需要用的依赖。

支付模块

数据库建表语句

DROP TABLE IF EXISTS `payment`;
CREATE TABLE `payment`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `serial` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '支付流水号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '支付表' ROW_FORMAT = Dynamic;

PaymentMain8001

@SpringBootApplication
public class PaymentMain8001 {
    public static void main(String[] args){
        SpringApplication.run(PaymentMain8001.class,args);
    }
}

Dao 层

@Mapper
public interface PaymentDao {
    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}
<?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.hangzhou.springcloud.dao.PaymentDao">
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial) values (#{serial})
    </insert>

    <resultMap id="BaseResultMap" type="com.hangzhou.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result 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 {
    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}
@Service
public class PaymentServiceImpl implements PaymentService {

    @Resource
    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
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;

    @PostMapping(value = "/payment/create")
    public CommonResult create(Payment payment) {
        int result = paymentService.create(payment);
        log.info("-----create方法执行结果:"+result);
        if(result > 0){
            return new CommonResult(200,"插入数据成功",result);
        }else{
            return new CommonResult(444,"插入数据失败",null);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        log.info("-----getPaymentById方法执行结果:"+payment);
        if(payment != null){
            return new CommonResult(200,"查询成功",payment);
        }else{
            return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
        }
    }
}
@Repository & @Mapper

@Repository 需要使用 @MapperScan(“xxx.xxx.xxx.mapper”) 进行扫描,然后生成Dao层的Bean才能被注入到Service层中。
@Mapper 不需要配置扫描地址,通过xml里面的namespace里面的接口地址,生成了Bean后注入到Service层中。

@RestController

@RestController 注解相当于 @Controller + @ResponseBody 两个注解的结合,返回 json 数据不需要在方法前面加 @ResponseBody 注解了,但使用@RestController这个注解,就不能返回 jsp,html 页面,视图解析器无法解析 jsp,html 页面。

@Controller
@ResponseBody
public @interface RestController {
@Slf4j

等同于 private final Logger logger = LoggerFactory.getLogger(当前类名.class) ,可以在代码中直接引用 log.info( ) 打印日志,但是前提是需要安装 Lombok 插件或 pom 文件引入。

@Autowired & @Resoure

@Autowired & @Resource:自动装配
@Autowired 默认优先按照类型去容器中找对应的组件:applicationContext.getBean(xxxDao.class),如果找到多个相同类型的组件,再将属性名称组为组件的id去容器中查找:applicationContext.getBean(“xxxDao”)。并且默认 @Autowired(required = true),表示注入的时候该 bean 必须存在,否则就会注入失败。
@Resource 默认是按照组件名称进行装配的;但是没有@Qualifier和@Autowired(required = false)功能。

@PathVariable & @RequestParam

@PathVariable 只能用于接收url路径上的参数,例如/blogs/1;而 @RequestParam 只能用于接收请求带的params,例如blogs?blogId=1。

  • 当URL指向的是某一具体业务资源(或资源列表)例如博客、用户时,使用@PathVariable
  • 当URL需要对资源或者资源列表进行过滤,筛选时,用@RequestParam

例如我们会这样设计URL:
/blogs/{blogId}
/blogs?state=publish 而不是 /blogs/state/publish 来表示处于发布状态的博客文章

热部署

模块pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

父类pom.xml

<!--热启动插件-->
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <fork>true</fork>
    <addResources>true</addResources>
  </configuration>
</plugin>

idea 设置中开启自动构建
在这里插入图片描述
Registry(mac快捷键option+command+shift+/)
在这里插入图片描述
在这里插入图片描述

消费者订单模块

pom.xml

<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>

OrderMain80

@SpringBootApplication
public class OrderMain80 {
    public static void main(String[] args){
        SpringApplication.run(OrderMain80.class,args);
    }
}

注册 RestTemplate

@Configuration
public class ApplicationContextConfig {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller 层

@RestController
@Slf4j
public class OrderController {
    private static final String PAYMENT_URL = "http://localhost:8001";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
        return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
    }
}
RestTemplate

RestTemplate 提供了多种便捷访问远程 Http 服务的方法,是一种简单便捷的访问 restful 服务模板类,是 Spring 提供的用于访问 Rest 服务的客户端模板工具集,实现80到8001的远程调用。
使用:使用 restTemplate 访问restful接口非常的简单粗暴,(url、requestMap、ResponseBean.class)这三个参数分别代表 REST 请求地址、请求参数、HTTP 响应转换被转换成的对象类型。

如果 8001 的PaymentController 请求中没有加@RequestBody注解

在这里插入图片描述
请求虽然返回插入数据成功,但是数据库中只有主键自增而没有实际值进入
在这里插入图片描述

构建 cloud-api-commons modules

将cloud2020中各个微服务组件中通用的entities部分进行重构
在这里插入图片描述
Lifecycle --> clean
在这里插入图片描述
Lifecycle --> install
在这里插入图片描述
MavenRepository
在这里插入图片描述
在 consumer-order80 和 provider-payment8001 的pom.xml文件中添加以下内容,然后删除entities包

<dependency>
    <groupId>com.hangzhou.springcloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>${project.version}</version>
</dependency>

重启项目完成
在这里插入图片描述

开启 Run Dashboard 功能

idea 2019.3 版本中是 Services
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值