springcloud 学习项目
- 概述
- 一、创建一个简单的springcloud项目
-
- 1_1、创建数据库和一个maven项目
- 1_2、创建springcloud-api模块
- 1_3 创建一个微服务提供者(springcloud-provider-dept-8001):
- 1_4创建服务消费者springcloud-consumer-dept-80
- 1_5创建eureka服务器(springcloud-eureka-7001)(已过时)
- 1_6 通过actuator完善eureka的监控信息
- 1_7搭建eureka集群环境
- 1_8在客户端实现负载均衡
- 1_9 使用feign替代RestTemplate(其内部集成了RestTemplate)
- 1_10分布式系统的延迟和容错处理方式
-
- Hytrix实现服务熔断(已过时)
-
- 1_10_1复制springcloud-provider-dept-8001生成一个新的服务提供者:springcloud-provider-dept-hystrix-8001
- 1_10_2添加Hystrix依赖到原有依赖中
- 1_10_3在application.yml中修改instance-id,方便区分
- 1_10_4修改启动类名为:DeptProviderHystrix_8001.java,并添加@EnableCircuitBreaker
- 1_10_5修改controller层(添加处理错误的功能)
- 1_10_6测试`http://localhost/consumer/dept/get/6`
- feign实现服务降级
- 熔断监控DashBoard监控请求(流量)
- 1_11路由网关Zuul(已过时)
- 1_12config
- -----------------------springcloud新技术-----------------------
- 一、Nacos:服务中心+配置中心
- GateWay网关
- 【附加】springcloud原理和思想
概述
1.springcloud是什么,为什么要学springcloud,不学springcloud又怎样呢。
一、创建一个简单的springcloud项目
本程序的结构图如下
1_1、创建数据库和一个maven项目
1_1_1 创建数据库db01,并创建表格dept,数据如下
1_1_2 创建maven项目并删掉src文件夹,然后添加依赖
点击查看dependencyManagement和dependencys的区别
1、关于打包方式:
pom:(父模块)用在父级工程或聚合工程中,用来做jar包的版本控制,必须指明这个聚合工程的打包方式为pom
war:(子模块)将会打包成war,发布在服务器上,如网站或服务。用户可以通过浏览器直接访问,或者是通过发布服务被别的工程调用
2、这里使用了propertieyManagement
来管理依赖的版本:
dependencies
即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)
dependencyManagement
里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。实际上只要在最大的项目内使用dependencyManagement之后(可以不在子模块中写同样的代码重复控制版本),那么子子模块、子子子模块都会默认使用dependencyManagement规定的版本。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.targer>1.8</maven.compiler.targer>
<junit.version>4.12</junit.version>
<lombok.version>1.16.18</lombok.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<!-- 1.:packaging使用pom的打包方式-->
<packaging>pom</packaging>
<!-- **************2.依赖管理:仅管理依赖,但不导入依赖***********-->
<dependencyManagement>
<dependencies>
<!-- springcloud的依赖(与其他依赖相比是pom类型)-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springBoot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 连接数据库和设计院-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- springBoot 启动器(内涵Mybatis)-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- **********以下是与日志测试相关的********-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!-- junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--配置打包插件build-->
<!-- <build>-->
<!-- <resources></resources> -->
<!-- </build>-->
1_2、创建springcloud-api模块
1_2_1.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>springCloud_01</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!-- 当前module中自己需要的依赖,如果父依赖中已经配制了版本,这里就不用写了-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
1_2_2 创建实体类pojo
@Data
@NoArgsConstructor
//使用链式写法(该类中的所有setter和getter方法的返回值都是this哦)
//@Accessors(prefix = "xxx")是忽略以xxx开头的属性,其余属性使用链式写法
@Accessors(chain = true)
public class Dept implements Serializable {
//Dept实体列,orm对象关系映射
private Long deptno;//主键
private String dname;
//这个数据是存在哪个数据库的字段~微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库
private String db_source;
public Dept(String name){
this.dname=dname;
}
}
1_3 创建一个微服务提供者(springcloud-provider-dept-8001):
1_3_1导入依赖
热部署工具非常好用,是指我们在程序中修改java代码之后能够生效。
使用方法很简单:1、添加依赖 2、修改服务器设置
参考文章
<dependencies>
<!-- 1、添加Pojo实体类-->
<dependency>
<groupId>org.junjun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 2、springboot和测试类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>com.junjun.test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>com.junjun.test</scope>
</dependency>
<!-- 3、数据库相关-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- 4、热部署工具:就是我们改动java代码后不用手动重启项目-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
1_3_2 配置application.yml
server:
port: 8001
# mybatis的配置
mybatis:
type-aliases-package: com.junjun.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
#spring服务器和数据库的配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
username: root
password: 3333
1_3_3 配置dao层,service层,controller层
1_3_3_1 dao/DeptDao:实体类的的增删改查方法的实现
使用@Mapper就能被对应的xml文档用namespace=""给找到(而且有提示)。
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
—DeptDao在sources中的对应的mapper.xml
虽然会爆红报错(xml中找不到Dept),但是可以正常运行
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间是对应的接口-->
<mapper namespace="com.junjun.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept(dname,db_source)
value (#{dname},DATABASE())
</insert>
<!-- 只有一个参数,因此#{}中可以随便写-->
<select id="queryById" resultType="Dept" parameterType="Long">
select * from dept where deptno=#{deptno};
</select>
<select id="queryAll" resultType="Dept">
select * from dept;
</select>
</mapper>
1_3_3_2 service层
--------service/DeptService
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
--------service/DeptServiceImpl
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll() ;
}
}
1_3_3_4 controller层
-------controller/DeptController
//提供Restful服务!
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
// 带占位符的url是springMVC的重要功能,请求中的{xxx}将会被传送到@PathVariable("xxx")中去
@GetMapping("/dept/get/{id}")
public Dept getDept(@PathVariable("id") Long id){
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List<Dept> getAll(){
return deptService.queryAll();
}
}
1_3_4配置开启springboot服务器的类
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
1_3_5对controller进行测试
1_4创建服务消费者springcloud-consumer-dept-80
1_4_1 导入依赖
<dependencies>
<!-- 1、添加Pojo实体类-->
<dependency>
<groupId>org.junjun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 2、springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1_4_2 在applicaction.yml中修改端口号
server:
port: 80
1_4_3 将RestTemplate注册到bean中
相当于在xml中用< bean/>注册,这种方式常用于框架中已经存在的类,自己定义的类通常会使用@Component在定义时就一步注册
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
1_4_4 配置controller层(通过restTemplate调用服务器的url)
1.消费者不应该有service层,而是调用服务提供者的service层,我们可以通过RestTemplate来申请调用服务提供者的url。
2.RestTemplate是Spring提供的一个访问Http服务的客户端类。服务消费者通过restTamplate给服务提供者发送HTTP请求并接受响应。。简单来说就是restTamplate可以用来调用请求并得到该服务器运行后的返回结果。
@RestController
public class DeptConsumerController {
@Autowire
private RestTemplate restTemplate;
private static final String REST_URL_PREFIX="http://localhost:8001";
//getForObject的三个参数是:url,返回值类型,占位符传参
@RequestMapping("/consumer/dept/add")
public boolean add(@RequestBody Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
//实现消费者和访问者完全解耦(用户访问需要经过一次转发)
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list", List.class);
}