模拟springcloud小型服务集群,创三个模块模拟三个服务端,注册服务到eureka,客户端使用ribbon、feign实现负载均衡。
1.创建一个空的maven工程,作为整个集群的父工程。导入项目所需要的一些依赖。如:springboot,springcloud依赖,springboot启动器,mysql数据库,日志相关的log4j,logback等。
主要问题:注意springboot,springcloud的版本之间的对应关系。
springcloud G版本对应springboot 2.1.x, F版本对应boot的2.0.X。这里在技术选型的时候要特别注意。版本问题不对会引发很多莫名其妙的bug,太麻烦。
<!--springcloud-->
<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>
2.在数据库创建表格,子工程中创建一个实体类,方便查询数据
@Data //构造器getter setter
@NoArgsConstructor //无参数构造器
@Accessors(chain = true) //开启链式编程
public class Dept implements Serializable {
private long deptno;
private String dname;
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
}
3.创建7001-7003,三个服务注册中心,节点与节点之间相互关联,防止服务崩溃,保持可用性。zookeeper是保持一致性,主节点崩溃后,重新建立新的leader节点,造成服务延迟。
//导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
//配置文件
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false #是否向注册中心注册自己
fetch-registry: false #false表示自己为注册中心
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
//主启动程序,添加对应的的注解。
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
4.分别创建三个服务端。端口采用8001-8003,修改了本地的host文件,localhost映射三个地址。导入依赖,写application.yml配置文件,添加注解,以及mapper,controller。
<dependencies>
<!--拿到实体类-->
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--连接数据库 数据库连接池-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--日志门面-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jetty 启动工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--导eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--监控配置actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
//相关配置文件
server:
port: 8001
# 配置spring
spring:
application:
name: springcloud-provider-dept
datasource:
url: jdbc:mysql://localhost:3306/db01
username: root
password: root
driver-class-name: org.gjt.mm.mysql.Driver
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-8001
5.建立客户端 ribbon实现方式
//引入依赖
<dependencies>
<!--引入ribbon及eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
//修改配置文件
server:
port: 80
eureka:
client:
register-with-eureka: false # 不想eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #url配置三个服务器地址
//添加相应注解
@SpringBootApplication
@EnableEurekaClient //开启客户端注解
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
//配置类
@Configuration
public class MyRestConfig {
@Bean
@LoadBalanced //配置ribbon实现RestTemplate的负载均衡,默认采用轮询的算法,可以自己重新相应的方法实现不同的负载均衡功能。
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//controller
@RestController
public class ConcumerDeptController {
@Autowired
// getForObject(String url, Class<T> responseType, Object... uriVariables)
private RestTemplate restTemplate;
// private static final String url_prefix="http://localhost:8001";
private static final String url_prefix = "http://springcloud-provider-dept"; //修改url地址为服务提供者的名字
@GetMapping("/consumer/dept")
public List<Dept> queryAll() {
return restTemplate.getForObject(url_prefix + "/dept", List.class);
}
@GetMapping("/consumer/dept/{id}")
public Dept queryById(@PathVariable("id") long deptno) {
return restTemplate.getForObject(url_prefix + "/dept/" + deptno, Dept.class);
}
@PostMapping("/consumer/dept/add")
public boolean addDept(Dept dept) {
return restTemplate.postForObject(url_prefix + "/dept/add", dept, Boolean.class);
}
}
5.2 建立客户端 feign实现方式
//引入依赖
<dependencies>
<!--引入feign及eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
//添加配置文件
server:
port: 80
eureka:
client:
register-with-eureka: false # 不想eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
//除了导入的feign依赖不同,其他与ribbon的依赖配置一样。
//开启注解
@SpringBootApplication
@EnableEurekaClient //开启eureka客户端注解
@EnableFeignClients(basePackages = {"com.hehe.springcloud","com.hehe.springcloud.service"}) //开启feign客户端注解支持
public class FeignDeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_80.class,args);
}
}
//"com.hehe.springcloud.service"这里,版本不同,如果不配置,可能会报错,提示你找不到service。
//配置类 与ribbon一样
@Configuration
public class MyRestConfig {
@Bean
@LoadBalanced //负载均衡 默认方式
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//controller
@RestController
public class ConcumerDeptController {
//会用feign面向接口编程,实现负载均衡
@Autowired
private DeptService deptService = null;
@GetMapping("/consumer/dept")
public List<Dept> queryAll() {
return this.deptService.queryAll();
}
@GetMapping("/consumer/dept/{id}")
public Dept queryById(@PathVariable("id") long deptno) {
return this.deptService.queryById(deptno);
}
@PostMapping("/consumer/dept/add")
public Dept addDept(Dept dept) {
return this.deptService.addDept(dept);
}
}
service包下的DeptService接口 与数据的类在同一模块下。
@Component @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT") //去查找对应名字的服务。 public interface DeptService { @GetMapping("/dept") public List<Dept> queryAll(); @GetMapping("/dept/{id}") public Dept queryById(@PathVariable("id") long deptno); @PostMapping("/dept/add") public Dept addDept(Dept dept); }
自定义负载均衡没有敲,其他的自己再总结一遍加深印象。
自己完成后的一些小问题:
版本问题;各种各样的超时问题,无法连接的问题,重启服务几次;一定要注意配置文件的格式,字符等。 比如冒号后面的空格,字母的大小写;自定义的负载均衡方法的包的位置,注意不要被主程序扫描,造成冲突; 导入依赖,添加配置,加注解,基本就这三步。熟悉其中的原理方法。