<packaging>pompackaging>
<properties>
<junit.version>4.12junit.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR8version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.3.4.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.20version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
dependencies>
dependencyManagement>
<artifactId>springcloud-api</artifactId>
<!-- 当前的Module自己需要的依赖,如果父依赖中已经配置了版本,然后这里就不用写了 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
package com.wbq.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@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;
}
/*
链式写法
Dept dept = new Dept();
dept.setDeptNo(11).setDname('sss').setDb_source('001');
*/
}
<dependencies>
<dependency>
<groupId>com.wbqgroupId>
<artifactId>springcloud-apiartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-testartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jettyartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
<version>1.4.6.RELEASEversion>
dependency>
dependencies>
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.wbq.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.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?useUnicode=true&characterEncoding=utf-8
username: root
password: root
<configuration >
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
configuration>
package com.wbq.springcloud.dao;
import com.wbq.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
package com.wbq.springcloud.service;
import com.wbq.springcloud.pojo.Dept;
import java.util.List;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
package com.wbq.springcloud.service;
import com.wbq.springcloud.dao.DeptDao;
import com.wbq.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
package com.wbq.springcloud.controller;
import com.wbq.springcloud.pojo.Dept;
import com.wbq.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping ("/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List<Dept> queryAll(){
return deptService.queryAll();
}
}
package com.wbq.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
DeptMapper.xml
<mapper namespace="com.wbq.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept (dname,db_source)
values (#{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>
<dependencies>
<dependency>
<groupId>com.wbqgroupId>
<artifactId>springcloud-apiartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
dependencies>
server:
port: 80
package com.wbq.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean { //@Configuration相当于Spring applicationContext.xml
@Bean
public RestTemplate getRestemplate(){
return new RestTemplate();
}
}
package com.wbq.springcloud.controller;
import com.wbq.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
//理解:消费者,不应该有Service层 ~
//RestFull
//RestTemplate ... 供我们直接调用就可以了! 注册到Spring 中
//(url,实体:map ,Class responseType)
@Autowired
private RestTemplate restTemplate; //提供多种便捷访问远程 http 服务的方法,简单的Restful服务模板 ~
private static final String REST_URL_PREFIX = "http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public boolean add(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);
}
}
package com.wbq.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
<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>springcloudartifactId>
<groupId>com.wbqgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>springcloud-eurka-7001artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eureka-serverartifactId>
<version>1.4.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
dependencies>
project>
server:
port: 7001
#Eureka 配置
eureka:
instance:
hostname: localhost #Eureka 服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #表示如果为false,则表示自己为注册中心
service-url: #监控页面 ~
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#Eureka 的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
DeptProvider_8001启动类加注解 ~~ @EnableEurekaClient
package com.wbq.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到eureka 中
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
#Eureka 的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka 上的默认描述信息
#info配置 ,点击描述可以看到的信息
info:
app.name: wbq-spring
company.name: blog.wbqstudy.com
//获取一些配置的信息,得到具体的微服务
@Autowired
private DiscoveryClient client;
//注册进来的微服务~,获取一些消息
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> service = client.getServices();
System.out.println("discovery => service:" + service);
//得到一个具体的微服务信息,通过具体的微服务 Id ,applicationName
List<ServiceInstance> instances = client.getInstances("S");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
启动类加注解 : @EnableDiscoveryClient //服务发现
#Eureka 配置
eureka:
instance:
hostname: localhost #Eureka 服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #表示如果为false,则表示自己为注册中心
service-url: #监控页面 ~
#单机 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联):
defaultZone: http://locahost:7002/eureka/
#Eureka 配置
eureka:
instance:
hostname: localhost #Eureka 服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #表示如果为false,则表示自己为注册中心
service-url: #监控页面 ~
defaultZone: http://eureka7001/eureka/
#集群(关联):
defaultZone: http://locahost:7002/eureka/,http://locahost:7003/eureka/
#集群(关联):
defaultZone: http://locahost:7001/eureka/,http://locahost:7003/eureka/
#集群(关联):
defaultZone: http://locahost:7001/eureka/,http://locahost:7003/eureka/
这样就实现了下面的效果,三个关联起来了
#Eureka 的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka 上的默认描述信息
#info配置 ,点击描述可以看到的信息
info:
app.name: wbq-spring
company.name: blog.wbqstudy.com
三个都注册
在本机 的 C:\Windows\System32\drivers\etc 目录下 hosts 文件下添加:
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
这样才有效果,这样做是做3个假的域名
没有这个域名,好像是不生效,我的加了这个假域名才生效
效果图如下:
访问7001 、7002、 7003 都有圈出来的,不用假域名,是不会显示的
.
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
org.springframework.cloud
spring-cloud-starter-ribbon
1.4.6.RELEASE
<!-- erueka -->
org.springframework.cloud
spring-cloud-starter-eureka
1.4.6.RELEASE
#负载均衡配置
#Euraka
eureka:
client:
register-with-eureka: false #不像euraka中注册自己
#实现随机选择一个服务,实现负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
@Configuration
public class ConfigBean { //@Configuration相当于Spring applicationContext.xml
//配置负载均衡实现RestTemplate
@Bean
@LoadBalanced //Ribbon
public RestTemplate getRestemplate(){
return new RestTemplate();
}
}
//Ribbon,我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@EnableEurekaClient //客户端
服务端口
server:
port: 8002
数据库名称
url: jdbc:mysql://localhost:3306/db02
id
instance:
instance-id: springcloud-provider-dept8002 #修改eureka 上的默认描述信息
每次刷新的数据都不一样,轮流3个服务器的访问,负载均衡
三个服务,去实现负载均衡
AvailabilityFilteringRule : 会先过滤掉挂掉的服务,或者说跳闸的服务,访问故障的服务 ~ ,对剩下的进行轮询
//IRule
//过滤已经崩溃的服务
// RoundRobinRule 轮询
// RandomRule 随机
// RetryRule :会先按照轮询获取服务~ ,如果服务获取失败,则会在指定的时间内进行重试
// AvailabilityFilteringRule : 会先过滤掉挂掉的服务,或者说跳闸的服务,访问故障的服务 ~ ,对剩下的进行轮询
@Bean
public IRule myRule(){
return new RandomRule();
}
引入注解 : @Configuration
在80服务启动类加入注解 : @RibbonClient(name = “SPRINGCLOUD-PROVIDER-DEPT”,configuration = WbqRule.class)
在微服务启动的时候就能去加载我们自定义的Ribbon类
//在微服务启动的时候就能去加载我们自定义的Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = WbqRule.class)
在80服务的config 新增的那个随机数Bean的位置Ctrl+鼠标左键,进去后,全部复制,在myrule文件夹复制,生成新的一个类,再更改名字,WbqRandomRule,删除刚刚复制的那个,有这个就好了
package com.wbq.myrule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class WbqRandomRule extends AbstractLoadBalancerRule {
//每个服务,访问5次~ , 换下一个服务(3个)
//total=0, 默认=0,如果=5, 我们指向下一个服务节点
//index=0, 默认=0,如果total=5, index+1
private int total = 0; //被调用的次数
private int currentIndex = 0; //当前是谁在提供服务~
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers(); //获得或者的服务
List<Server> allList = lb.getAllServers(); //获得全部的服务
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
// int index = this.chooseRandomInt(serverCount); //生成区间随机数
// server = (Server)upList.get(index); //从或者的服务中随机获取一个~
//-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if(total<5){
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex++;
if (currentIndex>upList.size()){
currentIndex = 0;
}
server = upList.get(currentIndex); //从活着的服务中,获取指定的服务来进行操作
}
//-================================================================
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
@Bean
public IRule myRule(){
return new WbqRandomRule(); //默认是轮询,现在我们自定义为~ WbqRandomRule
}
现在访问的话,就会进行每5个轮询,进入负载均衡
持续更新中。。。
package com.wbq.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心 IP 地址和端口号
@SpringBootApplication
@EnableEurekaClient //客户端
public class FeignDeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_80.class,args);
}
}
package com.wbq.springcloud.service;
import com.wbq.springcloud.pojo.Dept;
public interface DeptClientService {
public Dept queryById();
public Dept queryAll();
public Dept addDept(Dept dept);
}
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
<version>1.4.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
<version>1.4.6.RELEASEversion>
dependency>
这里的SPRINGCLOUD-PROVIDER-DEPT是在这里拿的
找到这个东西进行负载均衡 “SPRINGCLOUD-PROVIDER-DEPT“
package com.wbq.springcloud.service;
import com.wbq.springcloud.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public Dept queryAll();
@GetMapping("/dept/add")
public Dept addDept(Dept dept);
}
删除
//Ribbon,我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = “http://localhost:8001”;
private static final String REST_URL_PREFIX = “http://SPRINGCLOUD-PROVIDER-DEPT”;
把DeptClientService注册到spring里面去
该删除的删除,就剩现在的代码
package com.wbq.springcloud.controller;
import com.wbq.springcloud.pojo.Dept;
import com.wbq.springcloud.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService service = null;
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
}
}
这里的private DeptClientService service = null; 是因为没有实现类,所以等于null
在第一个方法中调用接口,
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return this.service.addDept(dept);
}
这里会报错,以为返回的是一个布尔值,所以要去springcloud-api项目中的那个接口中改,
@GetMapping("/dept/add")
public boolean addDept(Dept dept);
后面的一样
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return this.service.queryById(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return this.service.queryAll();
}
这里会报错,以为前面的那个接口,不是List < Dept >,需要去改
不想RIbbon一样那么多,比如看下面,就会很多,看起来不简洁清爽
@EnableFeignClients(basePackages = {“com.wbq.springcloud”}
作用是去扫描包
@ComponentScan(“com.wbq.springcloud”)
作用是扫描注解
红色下划线不用管,项目跑起来没问题
这样就完成了feign的负载均衡了
启动7001,8001,8002,feign服务测试一下
http://localhost/consumer/dept/list
就完成了