目录
1、SpringColud概述
1.1、什么是微服务
1.2、什么是SpringColud?
1.3、SpringColud的特点
2、SpringColud环境准备
2.1、创建父工程
2.2、修改pom.xml文件
2.3、服务提供者——创建子工程
2.4、编写启动类
2.5、编写User类
2.6、编写UserMapper接口
2.7、编写UserServiceImpl类
2.8、编写Controller类
3、创建服务调用者
3.1、yml文件
3.2、编写Pojo实体类
3.3、编写启动类
3.4、编写Controller类
3.5、启动测试
3.6、问题分析
4、Eureka注册中心
4.1、初识Eureka
4.2、Eureka能够做什么?
4.3、Eureka的使用
4.4、编写启动类
4.5、yml文件
4.6、启动测试
4.7、服务注册——user-service
4.8、注册服务-consumer-service
1、SpringColud概述
1.1、什么是微服务
"微服务”一词源于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到 Microservices
1、微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuLAPI 进行通信协作。
2、被拆分成的每一个小型服务都围绕着系统中的某一项或某些耦合度较高的业务功能进行构建,并且每个服务都维护着自身的数据存储、业务开发自动化测试案例以及独立部署机制。
3、由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。
4、微服务架构特点:
-
单一职责
-
服务粒度小
-
面向服务(对外暴露REST api)
-
服务之间相互独立
1.2、什么是SpringColud?
Spring Cloud 是一系列框架的有序集合。
Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
Spring Cloud 版本命名方式采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如:最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,Finchley,Greenwich,Hoxton。
Spring Cloud项目官方网址:Spring Cloud
1.3、SpringColud的特点
-
后台硬:作为Spring家族的一员,有整个Spring全家桶靠山,背景十分强大。
-
技术强:Spring作为Java领域的前辈,可以说是功力深厚。有强力的技术团队支撑,一般人还真比不了
-
群众基础好:可以说大多数程序员的成长都伴随着Spring框架,试问:现在有几家公司开发不用Spring? Spring Cloud与Spring的各个框架无缝整合,对大家来说一切都是熟悉的配方,熟悉的味道。
-
使用方便:相信大家都体会到了SpringBoot给我们开发带来的便利,而Spring Cloud完全支持Spring Boot的开 发,用很少的配置就能完成微服务框架的搭建。
2、SpringColud环境准备
首先,我们需要模拟一个服务调用的场景。
2.1、创建父工程
微服务中需要同时创建多个项目,为了方便演示,先创建一个父工程,然后后续的工程都以这个工程为父,实现maven的聚合。这样可以在一个窗口看到所有工程,方便讲解。在实际开发中,每个微服务可独立一个工程。
2.2、修改pom.xml文件
因为这个是父工程,所有把src包给删除掉,也可以不删,不过src包存在没有意义。
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.yh</groupId>
<artifactId>yh-springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
<mapper.starter.version>2.1.5</mapper.starter.version>
<mysql.version>5.1.46</mysql.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这里已经对大部分要用到的依赖的版本进行了 管理,方便后续使用。
2.3、服务提供者——创建子工程
新建一个项目user-service,对外提供查询用户的服务。
修改子工程的pom.xml文件
<?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>yh-springcloud</artifactId>
<groupId>cn.yh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
修改application.yml配置文件
server:
port: 8081
spring:
application:
name: user-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_crud?useSSL=false&useUnicode=true&characterEncoding=utf-8
username: root
password: xxx
mybatis:
type-aliases-package: cn.itssl.pojo
mapper-locations: classpath:mappers/*.xml
2.4、编写启动类
@SpringBootApplication
@MapperScan("cn.itssl.mapper")
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
2.5、编写User类
@Data
public class User {
private String id;
private String email;
private String username;
private String password;
private String phoneNum;
private Integer status;
}
2.6、编写UserMapper接口
这里使用的是注解形式,如果是多表查询还是推荐使用xml形式
@Repository
public interface UserMapper {
@Select("select * from users where id=#{id}")
User getUserById(String id);
}
2.7、编写UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserById(String id) {
return userMapper.getUserById(id);
}
}
2.8、编写Controller类
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/{id}")
public User queryById(@PathVariable String id) {
return userService.getUserById(id);
}
}
3、创建服务调用者
为了能够测试另一服务去远程调用user-service的查询用户功能,我们需要创建一个服务调用者consumer-service。
修改pom.xml配置文件
因为consumer-service去远程调用user-service的查询用户功能,所以在依赖中就不需要再添加mysql连接依赖以及mybatis依赖了。
<?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-day01</artifactId>
<groupId>com.itssl</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
3.1、yml文件
server:
port: 8082
spring:
application:
name: consumer-service
3.2、编写Pojo实体类
与user-service中的User一模一样,直接copy过来就可。
3.3、编写启动类
在启动类下添加一个远程调用工具的bean对象
@SpringBootApplication
@EnableEurekaClient //开启eureka客户端
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
//远程调用工具
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
3.4、编写Controller类
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public User queryById(@PathVariable("id") String id){
String url = "http://localhost:8081/user/" + id;
return restTemplate.getForObject(url, User.class);
}
}
3.5、启动测试
可以发现,我们访问的是8082端口下的consumer请求路径,查到了用户信息,那么就证明consumer-service远程调用user-service服务成功!
3.6、问题分析
存在什么问题?
-
在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
-
consumer需要记忆user-service的地址,如果出现变更,可能得不到通知,地址将失效
-
consumer不清楚user-service的状态,服务宕机也不知道
-
user-service只有1台服务,不具备高可用性
-
即便user-service形成集群,consumer还需自己实现负载均衡
其实上面说的问题,概括一下就是分布式服务必然要面临的问题:
-
服务管理
-
如何自动注册和发现
-
如何实现状态监管
-
如何实现动态路由
-
-
服务如何实现负载均衡
-
服务如何解决容灾问题
-
服务如何实现统一配置
4、Eureka注册中心
4.1、初识Eureka
在刚才的案例中,user-service对外提供服务,需要对外暴露自己的地址。而consumer-service(调用者)需要记录。
服务提供者的地址。将来地址出现变更,还需要及时更新。这在服务较少的时候并不觉得有什么,但是在现在日益复。
杂的互联网环境,一个项目可能会拆分出十几,甚至几十个微服务。此时如果还人为管理地址,不仅开发困难,将来测试、发布上线都会非常麻烦,这与DevOps的思想是背道而驰的。
DevOps的思想是系统可以通过一组过程、方法或系统;提高应用发布和运维的效率,降低管理成本。
4.2、Eureka能够做什么?
Eureka就好比是滴滴,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过 “心跳” 机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。
这就实现了服务的自动注册、发现、状态监控。
Eureka:就是服务注册中心(可以是一个集群),对外暴露自己的地址
提供者:启动后向Eureka注册自己信息(地址,提供什么服务)
消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
4.3、Eureka的使用
首先搭建一个eureka-server工程,创建一个项目 eureka-server ,启动一个Eureka Server Application服务注册中心。
修改pom.xml文件
<?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-day01</artifactId>
<groupId>com.itssl</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
4.4、编写启动类
@SpringBootApplication
@EnableEurekaServer //声明当前应用为eureka服务
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
4.5、yml文件
server:
port: 10086
spring:
application:
name: eureka-server
eureka:
client:
service-url:
# eureka 服务地址,如果是集群的话;需要指定其它集群eureka地址
defaultZone: http://127.0.0.1:10086/eureka
# 不注册自己
register-with-eureka: false
# 不拉取服务
fetch-registry: false
4.6、启动测试
启动 eureka-server 访问:http://127.0.0.1:10086
4.7、服务注册——user-service
注册服务,就是在服务上添加Eureka的客户端依赖,客户端代码会自动把服务注册到EurekaServer中。
添加依赖
我们在user-service中添加Eureka客户端依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改启动类,在启动类上开启Eureka客户端功能,通过添加 @EnableDiscoveryClient或者@EnableEurkaClient来开启Eureka客户端功能
@SpringBootApplication
@MapperScan("cn.itssl.mapper")
// @EnableDiscoveryClient 各个厂商的注册中心都可使用
@EnableEurekaClient //只针对eureka,开启Eureka客户端发现功能
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
修改配置文件
server:
port: 8081
spring:
application:
name: user-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_crud?useSSL=false&useUnicode=true&characterEncoding=utf-8
username: root
password: xxx
mybatis:
type-aliases-package: cn.itssl.pojo
mapper-locations: classpath:mappers/*.xml
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
# 更倾向使用ip地址,而不是host名
prefer-ip-address: true
# ip地址
ip-address: 127.0.0.1
# 续约间隔,默认30秒
lease-renewal-interval-in-seconds: 5
# 服务失效时间,默认90秒
lease-expiration-duration-in-seconds: 5
这里我们添加了spring.application.name属性来指定应用名称,将来会作为服务的id使用
测试
重启 user-service 项目,访问Eureka监控页面,我们发现user-service服务已经注册成功了
4.8、注册服务-consumer-service
与上面user-service操作一致,只不过就是yml配置文件和controller类不同
server:
port: 8082
spring:
application:
name: consumer-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
# 获取服务地址列表间隔时间,默认30秒
registry-fetch-interval-seconds: 10
修改处理器,修改代码,用DiscoveryClient类的方法,根据服务名称,获取服务实例。
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public User queryById(@PathVariable("id") String id){
// String url="http://localhost:8081/user/"+id;
//获取eureka中注册的user-service的实例
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = serviceInstances.get(0);
String url=serviceInstance.getUri().toString()+"/user/"+id;
return restTemplate.getForObject(url,User.class);
}
}