Eureka
基本知识
Eureka主要学习的是微服务的一些基本概念之类的,至于具体的操作其实都是在配置appolication.yml文件了,多看文档以及自己写过的demo就懂了。Eureka在微服务中承担的角色有三个,一个是注册中心server,一个是服务供给方porvider,以及接受用户请求的consumer,如果从启动类上面添加的注解这个角度来讲的话,其实proveder和consumer应该算是一类的,但是,从服务的角度来讲的话,还是应该把他两给区分开一下的。
server配置文件示例
application.yml配置文件
server:
port: 8761 # eureka默认端口号
spring:
application:
name: eureka-server # 应用的名称,最多用-,不要用特殊字符
eureka:
server:
eviction-interval-timer-in-ms: 10000 # 服务器定期做检测删除的时间间隔
renewal-percent-threshold: 0.85 # 心跳百分比
instance:
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} # 示例的名称
hostname: localhost # 主机名称
prefer-ip-address: true # 是否以ip的形式显示主机的信息
lease-renewal-interval-in-seconds: 5 # 心跳的时间间隔,要比服务器检测删除的时间短
client:
register-with-eureka: ${REGISTER_WITH_EUREKA:true} # 关闭自己注册自己的开关
fetch-registry: true # 是否拉取注册列表,就是服务名称和ip地址之间对应关系的一个列表
service-url:
defaultZone: ${EUREKA_SERVER_URL:http://localhost:8761/eureka}
上面最后的配置defaultZone这个就这样子写,不要写成其他的样式,Z一定要大写。记得在启动类上面添加注解,这个注解对应的就是注册中心的注解
@EnableEurekaServer // 开启eureka注册中心的功能
provider和consumer配置示例
application.yml配置文件
server:
port: 8080 # 服务的端口号
spring:
application:
name: eureka-client-a # 应用的名称,到时候会显示在Eureka注册中心的监控页面上
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka # 注册中心的地址,会往这个eureka注册中心中注册自己
register-with-eureka: true # 是否想自己注册自己
fetch-registry: true # 拉取服务列表
registry-fetch-interval-seconds: 10 # 间隔多久拉取服务信息
instance:
hostname: localhost
instance-id: ${eureka.instance.hostname}:${eureka.application.name}:${server.port}
prefer-ip-address: true # 是否需要以ip格式代表主机,这个选为true,方便我们进行调试
lease-renewal-interval-in-seconds: 10 # 发送心跳时间间隔
启动类上面添加服务端注解
@EnableEurekaClient
上传虚拟机无反应
docker明明开启了,但是却一直无法访问,搞了半天,看端口,重新克隆虚拟机,还是没用,租后发现是虚拟机的转发没开起来,因为之前关闭过虚拟机,导致转发的配置失效了,所以,得搞一下转发配置,这次一次性搞永久性的配置,不会开关机之后就失效的,修改配置文件
vim /etc/sysctl.conf
在文件末尾添加下面的内容
# For more information, see sysctl.conf(5) and sysctl.d(5).
net.ipv4.ip_forward=1
重启虚拟机就可以了。
RestTemplate
基本使用
这个主要用在测试方面,可以直接new出来一个RestTemplate对象,这个对象可以直接发送请求给特定的url地址,方便我们进行测试,
- getForObject()使用get方法访问地址,并将相应封装成我们指定的对象。
String result = restTemplate.getForObject(url, String.class);
- postForObject()则对应的是post方法,post请求有两种方式发送,一种是json方式,就是下面的这种, 里面传入的对象是封装了一些要传给controller的参数,到时候会转换成json发送给controller,controller会将json进行封装,变成一个对象参数的内容
String result = restTemplate.postForObject(url, user, String.class);
表单形式发送opost请求,这种相对相面的要复杂一点,需要自己构建表单参数。
// 构建表单参数
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("name","tangge");
map.add("age",26);
map.add("price",8000D);
String result = restTemplate.postForObject(url, map, String.class);
- 除了使用各种的请求方式ForObject()方法外,还可以使用请求方式ForEntity()方法
ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
这个方法会将响应的内容封装成一个entity,类似下面的这样子
<200 OK OK,ok,[Content-Type:"text/plain;charset=UTF-8", Content-Length:"2", Date:"Fri, 28 Apr 2023 13:16:44 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
补充知识点
Post请求传参有两种方式,一种是json传参,可以用@ResponseBody搭配对象参数接受
content-type = application/json;charset=utf-8
一种是表单传参,直接使用对象参数接收
content-type = application/x-www-form-urlencoded
Ribbon
用于client发送请求给provider的一个负载均衡
使用
导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
加载restTemplate的配置类上加注解@LoadBalanced
@SpringBootConfiguration
public class RestTemplateConfigurer {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
ribbon的实现流程:
- 拦截请求
- 获取主机名称
- 借助eureka发现实现服务发现,获取主机名称与ip的对应关系
- 通过负载均衡算法,得到要发送请求的ip地址
- 重新构建url
- 发送请求给provider
修改ribbon的负载均衡算法
ribbon默认的负载均衡算法是轮询算法,算法加上CAS自旋锁了,确保了并发情况下的原子性,保障轮询的成功。ribbo里面所有的算法都是IRule接口的实现类,找到这个接口,可以查看到可以使用的负载均衡算法
修改算法的方式有两种
一个服务(Provider)一个服务的去修改:
在改变负载均衡算法的时候需要使用到算法的全限定类名。改变算法的方式就是修改consumer配置文件application.yml
provider: # 服务提供者的名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 这里配置算法的全限定名称
全局修改
全局修改需要往容器里面注入一个IRule对象
@SpringBootConfiguration
public class RibbonConfigurer {
@Bean
public IRule rule() {
return new RandomRule();
}
}
还有一种是自己写一个算法实现IRule接口
pass
ribbon的一些配置
eureka:
enabled: true # 开启eureka的设置
http:
client:
enabled: false # false表示使用restTemplate发送请求的时候底层使用java.net.HttpUrlConnection发送请求,不支持连接池
# true则表示使用发送请求的工具发送请求,httpClient,支持连接池,需要加依赖
okhttp:
enabled: false # 和上面的类似,但是针对移动端,轻量级请求
OpenFeign
理解
按照我的理解,OpenFeign提供了一种服务间的远程调用的能力(这些服务在我的理解里面是同一等级的),主要用来服务于微服务场景。
设置超时时间
OpenFeign的默认超时时间是1s,超过了就会报错,如果想要修改超时时间的话需要修改ribbon的配置:OpenFeign只是封装了一些远程调用的功能,底层使用的还是ribbon,所以它的超时时间其实是ribbon的超时时间,修改配置自然也就得修改ribbon的了。
ribbon:
ReadTimeout: 3000 # 设置服务调用超时时间为3s
ConnectTimeout: 3000 # 链接服务超时时间3s
使用
在使用OpenFeign之前先知道,OpenFeign提供的是远程调用的功能,所以,这里需要两个觉得,一个调用方,一个是被调用方,而OpenFeign发挥作用的场所都在调用方这里,被调用方只需要提供服务,并且注册到Eureka上面就可以了。而在服务调用者这边,需要做的事情有以下几点
- 将被调用方的controller在调用方这里写成一个接口,并且配置好要调用方法的签名
/**
* value配置的是服务provider的名称
* 需要调用哪一个方法就复制哪一个方法的方法签名即可,不用全部复制
*/
@FeignClient(value = "order-service")
public interface UserOrderFeign {
// 将别调用服务的方法签名复制过来就可以了
@GetMapping("/doOrder")
public String doOrder();
}
- 启动类上面加上注解@EnableFeignClients
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
- 往容器里面注册好RestTemplate,注意一定要写LoadBalanced注解,这个注解关系到后面调用请求能否成功
@SpringBootConfiguration
public class RestTemplateConfigurer {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 在调用方的controller这里直接调用服务了
@GetMapping("/userDoOrder")
public String userDoOrder() {
System.out.println("用户访问");
String s = userOrderFeign.doOrder();
return s;
}
这样就完成服务的远程调用了,如果手撕一下OpenFeign框架的大致执行原理的话,就是下面这个样,主要的内容是JDK动态代理,使用RestTemplate去发送拼接好的请求。
UserOrderFeign userOrderFeign = (UserOrderFeign) Proxy.newProxyInstance(UserController.class.getClassLoader(), new Class[]{UserOrderFeign.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
GetMapping annotation = method.getAnnotation(GetMapping.class);
String[] paths = annotation.value();
String path = paths[0];
Class<?> aClass = method.getDeclaringClass();
String name1 = aClass.getName();
FeignClient annotation1 = aClass.getAnnotation(FeignClient.class);
String applicationName = annotation1.value();
String url = "http://" + applicationName + "/" + path;
String forObject = restTemplate.getForObject(url, String.class);
return forObject;
}
});
System.out.println(userOrderFeign.doOrder());
Feign的日志配置
Feign的日志等级如下,可在Logger类中查看(Feign包下的)
public enum Level {
/**
* No logging.
*/
NONE,
/**
* Log only the request method and URL and the response status code and execution time.
*/
BASIC,
/**
* Log the basic information along with request and response headers.
*/
HEADERS,
/**
* Log the headers, body, and metadata for both requests and responses.
*/
FULL
}
配置日志级别
@Bean
public Logger.Level level() {
return Logger.Level.FULL;
}
开启日志功能application.yml
logging:
level:
com.shuyepl.feign.UserOrderFeign: debug # 打印指定接口下面的日志信息
注意上面的接口限定名不要直接使用copy的方式,那种方式搞出来的是以斜线分割的,日志配置会失败。日志信息示例
Hystrix
参考资料:
标签:调用,String,SpringCloud,class,笔记,eureka,学习,public,ribbon From: https://www.cnblogs.com/shuyepl/p/17360086.html