会用到的知识:
-
Spring boot可以说是基于Spring且简化人工配置,开箱即用的框架。那spring cloud也可以说是spring boot的集成框架。springcloud里集成了很多常用的框架。
-
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。 -
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。Spring Cloud提供了让服务调用端具备负载均衡能力的Ribbon,通过和Eureka的紧密结合,不用在服务集群内再架设负载均衡服务,很大程度简化了服务集群内的架构。
1.工程搭建:Idea,JDK8,maven
建立一个父工程cloud-demo,引入了springboot,springcloud,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">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>user-service</module>
<module>consumer-demo</module>
<module>eureka-demo</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wrial</groupId>
<artifactId>cloud-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-demo</name>
<description>Demo project for Spring Boot</description>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<mapper.start.version>2.1.3</mapper.start.version>
<mysql.version>8.0.13</mysql.version>
</properties>
<dependencyManagement>
<dependencies>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.start.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.创建springboot子工程,因为要使用Eureka最少也需要两个moudle。(提供者和消费者)
consumer-demo:
第一步就是编写启动器(如果使用Springboot自动生成就不用),一定要放在其余目录的总目录下(为了能使用自动配置)。
@EnableDiscoveryClient//eureka
@SpringBootApplication
public class ConsumerApplication {
@Bean
@LoadBalanced//负载均衡,内置拦截器拦截RestTemplate的请求
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
第二步:创建目录结构并绑定数据库,编写pojo和controller
配置yml文件:主要包含端口配置和服务名称,和设置注册地址,可以加多个注册地址用逗号连接。
server:
port: 8082
spring:
application:
name: consumer
main:
allow-bean-definition-overriding: true
eureka:
client:
service-url:
defaultZone: http://localhost:8088/eureka/
导入依赖:现在一次先导入,后边就不用再重复导。里边有web启动器,和eureka,和ribbon。
<?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>cloud-demo</artifactId>
<groupId>com.wrial</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer-demo</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--包装着负载均衡算法 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
</project>
编写pojo,根据自己的数据库定义来编写pojo
package com.wrial.order.pojo;
import lombok.Data;
import java.util.Date;
@Data
public class Order {
private Integer id;
private String number;
private Date createtime;
private String note;
}
编写controller,此处在启动函数加上ribbon注解就可以不用注入client和discoveryclient,因为在RestTemplate上加注解就可以拦截restTemplate并将order-service替换(和我们前边写的拦截器差不多)
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
// @Autowired
// private RibbonLoadBalancerClient client;
// @Autowired
// private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public Order quaryById(@PathVariable("id") Integer id) {
String url = "http://order-service/order/" + id;//配置main中注解,拦截
return restTemplate.getForObject(url, Order.class);
}
}
编写user-service应该为order-service,当时写错了,这些小问题就先不管了。
第一步:导入用到的依赖
<?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>cloud-demo</artifactId>
<groupId>com.wrial</groupId>
<version>0.0.1-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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
第二步:编写启动类,声名eureka服务端,配置包扫描
@SpringBootApplication
@MapperScan("com.wrial.order.mapper")//一定要是tk包下
@EnableDiscoveryClient//eureka客户端,里面支持多种注册器兼容通用,如zookeeper
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
第三步:配置yml文件
server:
port: 8081
spring:
application:
name: order-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/Mybatis?serverTimezone=GMT&useSSL=FALSE
username: root
password: wrial.qq.com
main:
allow-bean-definition-overriding: true
mybatis:
type-aliases-package: com.wrial.order.pojo
#实现高可用的,Eureka集群,如果一个挂了还可以访问第二个
eureka:
client:
service-url:
defaultZone: http://localhost:8088/eureka/,http://localhost:8089/eureka/
第四步:编写pojo,并绑定数据库
@Table(name = "mybatis.order")
@Data
public class Order {
@Id
@KeySql(useGeneratedKeys = true)
private Integer id;
private String number;
private Date createtime;
private String note;
}
第五步:使用mybatis的mapper自动生成
package com.wrial.order.mapper;
import com.wrial.order.pojo.Order;
import tk.mybatis.mapper.common.Mapper;
public interface OrderMapper extends Mapper<Order> {
}
第六步:编写一个简单的service
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public Order SelectByPK(Integer pk){
return orderMapper.selectByPrimaryKey(pk);
}
}
第七步:编写一个controller
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/{id}")
public Order quaryByPk(@PathVariable("id") Integer id){
return orderService.SelectByPK(id);
}
}
编写eureka-demo
第一步:在maven加入服务端依赖,前面都是客户端
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
第二步:编写启动类,并声明是EurekaServer
@EnableEurekaServer
@SpringBootApplication
public class EurekaServer {
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class,args);
}
}
第三步:配置yml文件,声明端口,如果要配置多个eureka复制一个,并指定两个不同端口互相注册,多个eureka也一样,这样客户端就可以选择多个eureka服务端。再加上负载均衡算法,可以实现负载均衡。
server:
port: 8088
#设置默认url,连接另一个eureka,每次启动时换一下端口让两个Eureka互相连接形成集群
eureka:
client:
service-url:
defaultZone: http://localhost:8088/eureka/
#指定启动的ip地址
# instance:
# ip-address: 127.0.0.1
# prefer-ip-address: true
#配置eureka的name
spring:
application:
name: eureka-server
启动项目,查看注册情况
复制一个eureka,更改端口就可实现多个服务的,测试后会发现默认的负载均衡算法是轮询,也可以使用配置文件更改均衡算法。