[TOC]
单体应用存在的问题(为什么要用SpringCloud)
- 随着业务的发展,开发变得越来越复杂。
- 修改,新增某个功能,需要对整个系统进行测试,部署。
- 一个模块出现问题,很可能导致整个系统的崩溃。
- 开发团队同时对数据进行管理,容易产生安全漏洞。
- 各个模块使用同一种技术进行开发,各个模块很难根据实际的情况选择更适合的技术框架,局限性很大/
- 模块内容过于复杂,如果员工离职,交接难度,所需时间提升很大。
分布式,集群
集群:一台服务器无法承受高负荷并发的数据访问量,那就开十台服务器,十台不够就开一百台(物理层面)。很多人干同一件事情,来分担压力。
分布式:将一个复杂的问题差分成若干个小问题,将一个大型的项目拆分成若干个微服务来协同完成(软件设计层面)。将一个庞大的工作拆分成若干个小步骤,交给不同的人员来做,最后将所有结果整合实现大的需求。
服务治理的核型分为三部分:*注册中心*,*服务提供者*,*服务消费者*。
再分布式系统中,每个微服务启动时,将自己的信息储存到注册中心,这叫服务注册。
服务消费者通过注册中心获取到服务提供者的网络信息,通过该信息调用服务,这叫服务发现。
Spring Cloud Eureka
Eureka Server, 注册中心;
Eureka Client,所有需要进行注册的微服务通过 Eureka Client来连接到Eureka Server进行注册;
Eureka Server(注册中心)代码实现
创建一个父工程,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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> <modules> <module>eurekaaservice</module> <module>eurekaclicent</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.xxh</groupId> <artifactId>aispringcloud3</artifactId> <version>0.0.1-SNAPSHOT</version> <name>aispringcloud3</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> </repositories> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <!-- spring cloud依赖 注意版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.BUILD-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
在父工程下创建Module(eurekaserver),pom.xml
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.2.1.RELEASE</version> </dependency> </dependencies>
创建application.yml添加相应配置
server: port: 8761 eureka: client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://localhost:8761/eureka/
属性说明
server.port
:当前Eureka Service服务的端口;
eureka.client.register-with-eureka
:是否对当前 Eureka Service 服务当成客户端进行注册。
eureka.client.fetch-registry
:是否获取其他 Eureka Service 服务的数据;
eureka.client.service-url.defaultZone
:注册中心的访问地址。
创建启动类(EurekaServerApplication)
package com.xxh; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class,args); } }
注解说明
@SpringBootApplication
:声明当前类是一个spring boot 入口
@EnableEurekaServer
:声明当前类是一个 Eureka Service 微服务,提供注册和服务发现。就是注册中心;
- http://localhost:8761/ 访问成功进入
![]()
Eureka Client (服务提供者)代码实现
创建Client ,pmx.xml 代码
<dependencies> <!-- 服务提供者依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.0.2.RELEASE</version> </dependency> <dependency><!-- 启动不起来,再加入--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
添加application.yml; 配置
server: port: 8010 spring: application: name: provider eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true
属性说明
spring.application.name
:注册到服务中心的名称
eureka.client.service-url.defaultZone
:注册中心的访问地址
eureka.instance.prefer-ip-address
:是否将当前服务的 IP 注册到 Eureka Service。
启动类
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.http.EurekaApplications; @SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class,args); } }
将Client注册到Eureka,先启动Eureka再Client后进入到http://localhost:8761/
#### Eureka Client URUD操作
创建entity层 添加 JavaBean-Student; ()
public class Student { private long id; private String name; private int age; }
创建dao接口
package com.clicent.dao; import com.clicent.entity.Student; import java.awt.*; import java.util.Collection; public interface UserDao { Collection<Student> loadAll(); Student getById(Long id); void seveOrUpdate(Student stu); void dalete(long id); }
创建dao实现类
package com.clicent.dao.impl; import com.clicent.dao.UserDao; import com.clicent.entity.Student; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.HashMap; import java.util.Map; @Repository public class UserDaoImpl implements UserDao{ private static Map<Long,Student> studentMap; static { studentMap = new HashMap<>(); studentMap.put(1L,new Student(1L,"刘波",15)); studentMap.put(2L,new Student(2L,"洲书院",1475)); studentMap.put(3L,new Student(3L,"上级领导",15)); } @Override public Collection<Student> loadAll() { return studentMap.values(); } @Override public Student getById(Long id) { return studentMap.get(id); } @Override public void seveOrUpdate(Student stu) { studentMap.put(stu.getId(),stu); } @Override public void dalete(long id) { studentMap.remove(id); } }
创建Controller调用
package com.clicent.controller; import com.clicent.dao.impl.UserDaoImpl; import com.clicent.entity.Student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.Collection; @RestController //传入为json格式 public class UserController { @Autowired private UserDaoImpl udi; @GetMapping("/loadAll") public Collection<Student> load(){ return udi.loadAll(); } @GetMapping("/get/{id}") private Student get(@PathVariable("id") long id){ return udi.getById(id); } @PostMapping("/update") private void seveOrUpdate(@RequestBody Student stu){ udi.seveOrUpdate(stu); } @DeleteMapping("/delete/{id}") private void delete(@PathVariable("id") long id){ udi.dalete(id); } }
RestTemplate 的使用
- 什么是ResTemplate?
RestTemplate 是 Spring 框架提供的基于 REST 的服务组织,底层对HTTP进行请求及响应进行封装,提供了很多REST服务的方法,可以简化代码开发。
- 使用RestTemplate;
1,创建工程,pom.xml(可能需要添加)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2,创建实体类(与需要调用的实体类一致)
public class Student {
private long id;
private String name;
private int age;
}
3,编写Controller
package com.rest.controller;
import com.rest.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.List;
@RestController
@RequestMapping("/rest")
public class RestTemController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/loadAll")
public Collection<Student> load(){
return restTemplate.getForEntity("http://localhost:8010/loadAll", Collection.class).getBody();
}
@GetMapping("/get/{id}")
private Student get(@PathVariable("id") long id){
return restTemplate.getForEntity("http://localhost:8010/get/{id}",Student.class,id).getBody();
}
@PostMapping("/update")
private void seveOrUpdate(@RequestBody Student stu){
restTemplate.postForEntity("http://localhost:8010/update",stu,null).getBody();
}
@DeleteMapping("/delete/{id}")
private void delete(@PathVariable("id") long id){
restTemplate.delete("http://localhost:8010/delete",id);
}
}
4,编写启动类
package com.rest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class RestTemperatureApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemperatureApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服务消费者 consumer
创建 Maven 工程,pom.xml;
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.1.RELEASE</version> </dependency> </dependencies>
添加application.yml
server: port: 8020 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true spring: application: name: consumer
创建启动类
package com.cn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class,args); } @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
controller层
package com.cn.controller; import com.cn.entity.Student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.Collection; @RestController @RequestMapping("/controller") public class ConsumerController { @Autowired private RestTemplate restTemplate; @GetMapping("/loadAll") public Collection<Student> load(){ return restTemplate.getForEntity("http://localhost:8010/loadAll", Collection.class).getBody(); } @GetMapping("/get/{id}") private Student get(@PathVariable("id") long id){ return restTemplate.getForEntity("http://localhost:8010/get/{id}",Student.class,id).getBody(); } @PostMapping("/update") private void seveOrUpdate(@RequestBody Student stu){ restTemplate.postForEntity("http://localhost:8010/update",stu,null).getBody(); } @DeleteMapping("/delete/{id}") private void delete(@PathVariable("id") long id){ restTemplate.delete("http://localhost:8010/delete",id); } }