SpringCloud 入门
系列链接:
- GitHub:源码
- SpringCloud(1)–入门、版本、环境搭建
- SpringCloud(2)–服务注册与发现(Eureka、Zookeeper、Consul)
- SpringCloud(3)–服务调用(Ribbon、OpenFeign)
- SpringCloud(4)–服务降级(Hystrix、降级、熔断、监控)
- SpringCloud(5)–服务网关(GateWay)
- …
版本的选择
查看SpringCloud和SpringBoot之间版本的依赖关系:
- https://spring.io/projects/spring-cloud#overview
- https://start.spring.io/actuator/info,返回详细json信息
部分组件停用
首先连接下各个组件:
-
服务注册中心:EUREKA
-
服务负载均衡与调用:NETFLIX OSS RIBBON
-
服务负载与调用:NETTFLIX
-
服务熔断降级:HYSTRIX
-
服务网关:Zuul
-
服务分布式配置:SpringCloud Config
-
服务开发:SpingBoot
SpringCloud升级后,部分组件停用:
- Eureka 停用,可以使用 Zookeeper 作为服务注册中心
- 服务调用,Ribbon 准备停更,代替为 LoadBalance
- Feign 改为 OpenFeign
- Hystrix 停更,改为 resilence4j 或者阿里巴巴的 sentienl
- Zuul 改为 gateway
- 服务配置 Config 改为 Nacos
- 服务总线 Bus 改为 Nacos
环境搭建
接下来我们会搭建一个订单-支付模块微服务。
父工程创建
父工程依赖
<groupId>com.moke.springcloud</groupId>
<artifactId>cloud1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!--统一管理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>8.0.18</mysql.version>
<druid.verison>1.1.16</druid.verison>
<mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison>
</properties>
<!--子模块继承之后,提供作用:锁定版本+子module不用谢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.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- MySql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.verison}</version>
</dependency>
<!-- mybatis-springboot整合 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.verison}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.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
在pom.xml文件中使用了之前没有用过的 dependencyManagement,其通常用在项目中对顶层的父POM中,它能让其所有子项目引用一个依赖而不用显式的列出版本号。此外,dependencyManagement 只是声明依赖,并不实现引入,子项目如果不声明依赖,则不会从父项目中继承下来。 -
maven跳过单元测试
-
父工程创建后,可以使用 maven install 发布到仓库方便子工程继承。
-
idea忽略显示 .idea 文件夹与 .iml 文件
支付模块
创建Module
父工程右键 New->Module,创建之后父POM会出现:
同时由于使用了dependencyManagement,子工程的POM如下:
修改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>
<!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
</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>
修改application.yml
resources下,如果没有则新建
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
# 当前数据源操作类型
type: com.alibaba.druid.pool.DruidDataSource
# mysql驱动类
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.moke.springcloud.entities
主启动类
com.moke.springcloud包下新建类PaymentMain8001:
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8001.class,args);
}
}
业务类
sql
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=utf8
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable{
private long id;
private String serial;
}
entity类
@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);
}
}
dao层:
@Mapper
public interface PaymentDao {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
mapper配置文件类
<?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.moke.springcloud.dao.PaymentDao">
<insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial) values(#{serial});
</insert>
<resultMap id="BaseResultMap" type="com.moke.springcloud.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和serviceImpl
service:
public interface PaymentService {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
serviceImpl:
public interface PaymentService {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
controller
@RestController
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
@Resource
private PaymentService paymentService;
@PostMapping("/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("****插入结果:{result}");
if(result>0){
return new CommonResult(200,"插入成功",result);
}else {
return new CommonResult(444,"插入失败");
}
}
@GetMapping("/get/{id}")
public CommonResult 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,"无记录");
}
}
}
订单模块
创建Module
新建module、pom文件、主启动类与支付模块类似,这里不再赘述。
yml配置文件
server:
port: 80
业务类
复制pay模块的实体类,entity类,之后写controller类
作为消费者类没有service和dao,而是需要调用pay模块的方法,并且这里还没有微服务的远程调用,那么如果要调用另外一个模块,则需要使用基本的api调用,可以使用RestTemplate调用pay模块。
RestTemplate介绍
原本发送Http请求我们会使用封装好的HttpClient工具类,而Spring为我们提供了RestTemplate工具集。它提供了多种便携访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类。
- 创建配置类,将restTemplate注入到容器
@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 在需要使用的controller中依赖注入就可进行使用,如下使用restTemplate调用支付模块
@RestController
@Slf4j
@RequestMapping("/consumer")
public class OrderController {
private static final String PAYMENT_URL = "http://localhost:8001";
@Resource
private RestTemplate restTemplate;
@GetMapping("/payment/create")
public CommonResult<Payment> create(Payment payment){
return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
}
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
}
重构
新建一个模块,将重复代码抽取到一个公共模块中
-
创建commons模块
-
抽取公共pom
<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>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.7</version>
</dependency>
注:hutol是一个第三方的Java工具类库,详情参考:文档
3,entity和实体类放入commons中,并删除其他模块中的
4,使用maven,将commone模块打包(install),其他模块引入commons模块
<!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.moke.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>