1.微服务入门案例
微服务是把许多单个服务和功能分为各个小单位组合起来,通过配置中心分配服务的调用,从而优化网络服务,也使得用户的服务更加便捷和安全。
1.1 项目结构图
![](https://i-blog.csdnimg.cn/blog_migrate/4db1bad4a7c27c55c8f3a162a6da9f36.png)
说明:通过nacos注册中心,管理服务的三方
1.2服务提供方
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
@RestController
public class ProviderController {
@Value("${server.port:8080}")
private String server;
@GetMapping(value = "/provider/echo/{msg}")
public String doEcho(@PathVariable String msg){
return server+"say:Hello nacos Discovery"+msg;
}
}
}
1.3 服务消费方
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
/**创建RestTemplate */
@Bean
@LoadBalanced
public RestTemplate loadBalanceRestTemplate(){
return new RestTemplate();
}
@RestController
public class ConsumerController{
@Autowired
private RestTemplate loadBalanceRestTemplate;
//负载均衡客户端对象(基于此对象可以从nacos中获取服务列表,并且基于一定的算法)
//从列表中获取一个服务实例
@Autowired
public LoadBalancerClient loadBalancerClient;
@Value("${server.application.name}")
private String appName;
@GetMapping("/consumer/doRestEcho1/")
public String doRestEcho1(){
//调用谁?sca-provider中的一个Url
String url1="http://localhost:8081/provider/echo/"+appName;
String url2="http://localhost:8082/provider/echo/"+appName;
String url3="http://localhost:8080/provider/echo/"+appName;
String urls[]=new String[]{url1,url2,url3};
//随机获取一个小于urls数组长度的整数
int n=new Random().nextInt(3);
System.out.println("n="+n);
//如何调用?
String result= restTemplate.getForObject(urls[n], String.class);
//return server +"say Hello"+ msg;
return result;
}
}
}
2 .服务消费方调用提供方
通过依赖注解的方式,服务方会调用启用的多个消费方中的一个,调用策略采用的时默认的轮询
关键代码:
/**@Autowired 注解描述属性时,会告诉Spring框架,要优先按照属性类型进行对象的查找和注入
* 假如此类对象存在多个,此时还会按照属性名进行查找和比对,有相同的直接注入DI
* 没有的则出错 ,当然也可以在属性上添加@Qualifiler(”bean的名字“)指定要注入的对象*/
@Autowired
private RestTemplate loadBalanceRestTemplate;
//负载均衡客户端对象(基于此对象可以从nacos中获取服务列表,并且基于一定的算法)
//从列表中获取一个服务实例
@Autowired
public LoadBalancerClient loadBalancerClient;
2.1 手动写负载均衡
手写负载均衡的方式在于对多个服务地址封装进数组,选取数组中的一个元素进行调用
@GetMapping("/consumer/doRestEcho1/")
public String doRestEcho1() {
//调用谁?sca-provider中的一个Url
String url1="http://localhost:8081/provider/echo/"+appName;
String url2="http://localhost:8082/provider/echo/"+appName;
String url3="http://localhost:8080/provider/echo/"+appName;
String urls[]=new String[]{url1,url2,url3};
//随机获取一个小于urls数组长度的整数
int n=new Random().nextInt(3);
System.out.println("n="+n);
//如何调用?
return result= restTemplate.getForObject(urls[n], String.class);
}
2.2 1.0升级版写法:RestTemplate+LoadbalancerClient
使用@LoadbalancerClient能动态拼接服务的端口号,以及服务方法名,组合形成网址中的参数
@GetMapping("/consumer/doRestEcho2/")
public String doRestEcho2(){
String serverId ="sca-provider";//这个名字要在nacos的服务列表中
ServiceInstance choose =loadBalancerClient.choose(serverId);
String ip=choose.getHost();
int port =choose.getPort();
//String url= "http://"+ip+":"+port+"/provider/echo/"+msg;
String url =String.format("http://%s:%s/provider/echo/%s",ip,port,appName);
return restTemplate.getForObject(url,String.class);
}
2.3 1.1升级版写法RestTemplate+@LoadBalanced
@LoadBalanced简化了ip请求端口号和方法名,使对象拼接到网页之中
#修改配置的restTemplate
@Bean
@LoadBalanced
public RestTemplate loadBalanceRestTemplate(){
return new RestTemplate();
}
#修改注解
@Autowired
private RestTemplate loadBalanceRestTemplate;
@GetMapping("/consumer/doRestEcho3/")
public String doRestEcho3(){
String serverId ="sca-provider";
String url =String.format("http://%s/provider/echo/%s",serverId,appName);
return loadBalanceRestTemplate.getForObject(url,String.class);
}
总结:消费方调用提供方运用了spring框架的思想,将其中的资源交给spring框架进行管理,运用bean注解的方式将资源交给sprin管理。
2.4 2.0升级版写法:@EnableFeignClients+@FeignClient
1.在消费方添加openfeign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.在启动类添加@EnableFeginClients注解
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {…}
3.创建一个接口文档,定义Http请求API,基于此API借助OpenFeign访问远端服务
@FeignClient(name="sca-provider")//sca-provider为服务提供者名称
interface RemoteProviderService{
@GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
public String echoMessage(@PathVariable("string") String string);
}
说明:,@FeignClient描述的接口底层会为其创建实现类。
4.创建FeignConsumerController中并添加feign访问
@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
@Autowired
private RemoteProviderService remoteProviderService;
/**基于feign方式的服务调用*/
@GetMapping("/echo/{msg}")
public String doFeignEcho(@PathVariable String msg){
//基于feign方式进行远端服务调用(前提是服务必须存在)
return remoteProviderService.echoMessage(msg);
}
}
5.启动消费者服务,在浏览器中直接通过feign客户端进行访问
3.负载均衡相关机制及知识点
3.1 并行运行多线程
勾选允许多线程
3.2 线程交给nacos管理
3.3 心跳提交底层
public class TimerTests {
public static void main(String[] args) {
//通过timer对象可以启动一个定时任务
Timer timer=new Timer();
//基于timer对象启动并执行任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(System.currentTimeMillis());
}
},1000,1000);
}
}
4.面试相关知识点
- 在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
- 对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
- 服务消费方是如何调用服务提供方的服务的?(RestTemplate)
- @Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
- @Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
- Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
- Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
- Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
- @LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
- 我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)