- 修改控制层对服务层的访问路径
- 使用Ribbon负载均衡,我们这里不应该写死。而应该通过id名(服务提供者),进行获取 SpringCloud-provider-dept
// 设置服务层的前缀为常量 //private static final String REST_URL_PREFIX="http://localhost:8081"; // 使用Ribbon负载均衡,我们这里不应该写死。而应该通过id名(服务提供者),进行获取 SpringCloud-provider-dept private static final String REST_URL_PREFIX="http://SpringCloud-provider-dept";
package com.jsxs.controller; import com.jsxs.pojo.Dept; 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 javax.annotation.Resource; import java.util.List; @RestController public class DeptConsumerController { //注意: 这里我们只是引入了实体类的数据,并没有引入service接口 //思考: 消费者界面不应该存在Dao层也不应该存在Service层,该如何使用服务呢 //RestTemplate ... 我们直接调用就行,但需要注入到Spring中 @Resource // (URI url, 实体 map,Class<T> responseType) 地址---- 实体 ----返回类型.class private RestTemplate restTemplate; // 提供多种便捷访问远程 访问http服务的方法,简单的Rest // 设置服务层的前缀为常量 //private static final String REST_URL_PREFIX="http://localhost:8081"; // 使用Ribbon负载均衡,我们这里不应该写死。而应该通过id名(服务提供者),进行获取 SpringCloud-provider-dept private static final String REST_URL_PREFIX="http://SpringCloud-provider-dept"; // 根据id进行数据的查找 @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long deptno){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/queryById/"+deptno,Dept.class); } // 添加数据 @RequestMapping("/consumer/dept/add") public boolean add(Dept dept){ return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class); } // 查找全部数据 @RequestMapping("/consumer/dept/all") public List<Dept> all(){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/all",List.class); } }
结论: Eureka和Ribbon整合之后,客户端可以直接调用,不再用关心我们的IP地址和端口号。 为什么? ①因为我们实现了负载均衡,所以客户端像跳哪个服务器,负载均衡会帮助我们寻找。②我们在controller做了手脚,通过注册服务的id进行跳转。
3.使用Ribbon实现负载均衡
流程图:
(Ribbon有两个步骤:1.去Eureka集群中查找可用的服务列表;2.通过负载均衡的算法,从服务提供者中选择一个看起来比较OK的)
1.新建两个服务提供者Moudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002
CREATE DATABASE db03; USE db03; CREATE TABLE dept( deptno BIGINT(20) Not Null PRIMARY KEY AUTO_INCREMENT, dname VARCHAR(60) DEFAULT NULL, db_source VARCHAR(60) DEFAULT NULL ); INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('售后部',DATABASE());
2.参照springcloud-provider-dept-8001 依次为另外两个Moudle添加pom.xml依赖 、resourece下的mybatis和application.yml配置,Java代码
3.启动所有服务测试(根据自身电脑配置决定启动服务的个数),访问http://eureka7001.com:7001/查看结果
4.进行用户访问
第一次刷新
第二次刷新
Eureka
内存
以上这种每次访问http://localhost/consumer/dept/list随机访问集群中某个服务提供者,这种情况叫做轮询,轮询算法在SpringCloud中可以自定义。
4.自定义负载均衡算法
如何切换或者自定义规则呢?
(1).切换系统已有均衡算法
默认的是轮询,如果我们需要切换。那么我们就自己配置一个类
@Bean public IRule myIRule(){ return new RandomRule(); }
1.在springcloud-provider-dept-80模块下的ConfigBean中进行配置,切换使用不同的规则
package com.jsxs.config; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration // 相当于application.xml文件 public class ConfigBean { // IRule : /** * 1.AvailabilityFilteringRule 先过滤掉奔溃(跳匝)的服务,对剩下的服务进行轮询 * 2.RoundRobinRule 轮询 《默认》 * 3 .RoundRobinRule 随机 * 4. RetryRule 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内运行。 * */ @LoadBalanced // 配置负载均衡,只需要添加一个注解就可以 @Bean // 把RestTemplate注入到Spring中去 public RestTemplate getRestTemplate(){ return new RestTemplate(); } // 启用随机作为Ribbon的算法 @Bean public IRule myIRule(){ return new RandomRule(); } }
2.启动测试: 发现真的变成随机负载了。
(2).自定义负载均衡算法
1.切记我们自定义的负载均衡算法,不能被Spring扫描到。所以我们自定义的算法需要放在启动类的上一级
自定义的算法会覆盖默认的算法均衡 FooConfiguration必须是@Configuration,但请注意,它不在主应用程序上下文的@ComponentScan 中,否则将由所有@RibbonClients共享。如果您使用@ComponentScan(或@SpringBootApplication) ,则需要采取措施避免包含(例如将其放在一个单独的,不重叠的包中,或者指定要在@ComponentScan)。
2.自定义配置的java文件 murule/JsxsRandomRule.java
package com.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 JsxsRandomRule extends AbstractLoadBalancerRule { public JsxsRandomRule() { } @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 (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) { } }
3.在启动类上声明注解
package com.jsxs; import com.myrule.JsxsRule; 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; @SpringBootApplication @EnableEurekaClient // 在微服务启动的时候,就会加载我们自定义的均衡算法。 @RibbonClient(name = "SpringCloud-provider-dept",configuration = JsxsRule.class) // 服务端的ID名 自定义配置的类 public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
- 切换成我们自定义的负载均衡 myrule/JsxsRule.java
package com.myrule; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JsxsRule { // 启用随机作为Ribbon的算法 @Bean public IRule myIRule(){ return new JsxsRandomRule(); } }
5.测试无误。