<!--依赖user-common公共模块-->
<dependency>
<groupId>cn.itsource</groupId>
<artifactId>springcloud-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id){
return new User(id,"古老板","我创建了学荣ui port:1000");
}
}
测试一下能够获取到User对象localhost:1000/user/11
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
使用RestTemp调用user-server获取结果 - 使用ip:端口调用 -> “http://localhost:1000/user/”+id;
@RestController
public class PayController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/pay/user/{id}")
public User getUserById(@PathVariable("id") Long id){
String url = "http://localhost:1000/user/"+id;
return restTemplate.getForObject(url, User.class);
}
}
负载均衡Ribbon的工作原理
支付服务要调用用户服务,需要指定用户名"user-server".
因为用户微服务做了集群,那么"user-server"服务名对应了两个端口,Ribbon会通过服务名找到两个端口,根据负载均衡算法(轮询,随机等)选中其中一个实现调用。
多建立一个相同的user-server,注意:端口不一样 ,instance-id不一样 ,其他的一样
pay-server导入Ribbon的jar包
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>
加上 @LoadBalanced相当于给予RestTemplate对象负载均衡的能力
//相当于给予RestTemplate对象负载均衡的能力
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
修改pay-servercontroller,让RestTemplate使用服务名的方式实现调用 -> “http://user-server/user/”+id
@RestController
public class PayController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/pay/user/{id}")
public User getUserById(@PathVariable("id") Long id){
String url = "http://user-server/user/"+id;
return restTemplate.getForObject(url, User.class);
}
}
//配置负载均衡算法为 - 随机
@Bean
public IRule randomRule(){
return new RandomRule();
}
首先我们重新创建一个项目order-server(订单服务)
需要web,eureka-client , user-comm , openfeign包
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 集成Web的jar包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--依赖user-common公共模块-->
<dependency>
<groupId>cn.itsource</groupId>
<artifactId>springcloud-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--集成Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
主配置类:@EnableFeignClients
@SpringBootApplication
@EnableFeignClients //开启Feign客户端
public class OrderServerApplication4000
{
public static void main( String[] args )
{
SpringApplication.run(OrderServerApplication4000.class);
}
}
@FeignClient(value = "user-server")//写远程调用的服务名
public interface MyFeignClient {
//url,参数,返回值类型必须一样
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id);
}
@RestController
public class OrderController {
@Autowired
private MyFeignClient myFeignClient;
@GetMapping("/order/user/{id}")
public User getUserById(@PathVariable("id") Long id){
return myFeignClient.getUserById(id);
}
}
#配置ribbon
user-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
雪崩效应:类似雪崩一样,滚雪球越滚越大
当一个微服务出问题,和该微服务有调用关系的微服务也会挂掉,以此类推可能导致大量微服务挂掉。
为了解决雪崩效应带来的问题,hystrix提供了如下的机制:
正常情况下,断路器处于关闭状态
如果调用持续出错或者超时,电路被打开进入熔断状态,后续一段时间内所有的调用都会被拒绝
一段时间以后,保护器会尝试进入半熔断状态,允许少量请求进行尝试。
如果调用仍然失败,则回到熔断状态
如果调用成功,则回到电路闭合状态
<!--集成hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
@EnableCircuitBreaker开启Hystrix
@SpringBootApplication
@EnableCircuitBreaker
public class PayServerApplication2000
{
public static void main( String[] args )
{
SpringApplication.run(PayServerApplication2000.class);
}
//相当于给予RestTemplate对象负载均衡的能力
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
//配置负载均衡算法为 - 随机
@Bean
public IRule randomRule(){
return new RandomRule();
}
}
@RestController
public class PayController {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "payFallback")
@GetMapping("/pay/user/{id}")
public User getUserById(@PathVariable("id") Long id){
String url = "http://user-server/user/"+id;
return restTemplate.getForObject(url, User.class);
}
//拖底方法
public User payFallback(@PathVariable("id") Long id){
return new User(-1L,"无此用户","用户服务不可用");
}
}
配置文件:
#开启hystrix
feign:
hystrix:
enabled: true
@FeignClient(value = "user-server",fallback = MyFeignClientFallback.class)//写远程调用的服务名
public interface MyFeignClient {
//url,参数,返回值类型必须一样
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id);
}
注意:
@Component
public class MyFeignClientFallback implements MyFeignClient{
@Override
public User getUserById(Long id) {
return new User(-1L,"无此用户","用户服务无法访问");
}
}
zuul作为独立的应用,zuul作为微服务群的请求入口,保护着微服务的安全,可以通过zuul实现,统一的权限验证、限流、请求日志/监控,负载均衡(请求分发等)功能,–>有点像之前学习的拦截器
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
dependencies>
@SpringBootApplication
@EnableZuulProxy
public class ZuulServerApplication5000
{
public static void main( String[] args )
{
SpringApplication.run(ZuulServerApplication5000.class);
}
}
http://+zuul的ip:zuul的port/服务名字/资源路径
如:http:// localhost:5000/ pay-server /pay/user/1
server:
port: 1020
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1010/eureka/ #注册中心服务端的注册地址
instance:
prefer-ip-address: true
instance-id: zuul-server:1020
spring:
application:
name: zuul-server
# 配置zuul
zuul:
ignored-services: "*" #禁止浏览器 使用服务名的方式去访问目标服务
routes:
pay-server: "/pay/**"
order-server: "/order/**"
host: #zuul主机超时
connect-timeout-millis: 30000 #HTTP连接超时要比Hystrix的大
socket-timeout-millis: 30000 #socket超时
# 下面ribbon和hystrix都可以配
ribbon: #ribbon超时
ReadTimeout: 30000
ConnectTimeout: 30000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 40000
步骤:
@Component
public class LoginCheckFilter extends ZuulFilter {
//过滤器类型
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
//顺序
@Override
public int filterOrder() {
return 1;
}
//判断是否应该检查登录,返回true表示要做登录检查
@Override
public boolean shouldFilter() {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
//判断url是否是登录请求
String requestURI = request.getRequestURI();
if(StringUtils.hasLength(requestURI)&&requestURI.endsWith("login")){
return false;
}
return true;
}
//做登录检查,如果请求头中没有token,说明没有登录
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
HttpServletResponse response = currentContext.getResponse();
//设置编码
response.setContentType("application/json;charset=utf-8");
//获取请求头token,判断是否登录
String token = request.getHeader("token");
request.getHeader("token");
if(!StringUtils.hasLength(token)){
//如果token为空,表示没有登录,返回提示登录信息,阻止请求继续往下执行,不放行
Map<String,Object> result = new HashMap<>();
result.put("success",false);
result.put("message","您还未登录,请先登录");
try {
response.getWriter().print(JSON.toJSONString(result));
//并且阻止请求继续往下执行:不放行
currentContext.setSendZuulResponse(false);
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
微服务架构中,每个项目都有一个yml配置,管理起来麻烦。分布式配置中心的作用就是用来管理微服务的配置
在spring cloud config 组件中,分两个角色,一是config server,二是config client。
配置中心可以和svn,git集成,但是推荐使用github 集成使用
仓库中新建文件,将项目中配置文件的内容拷贝到码云创建的文件中
导入jar包(eureka-client、web、spring-cloud-config-server)
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
dependencies>
主配置类:@EnableConfigServer //开启配置中心服务
@SpringBootApplication
@EnableConfigServer //开启配置中心服务
public class ConfigServerApplication6000 {
public static void main( String[] args )
{
SpringApplication.run(ConfigServerApplication6000.class);
}
}
配置文件:配置码云仓库的访问链接,用户名,密码
server:
port: 6001
eureka:
client:
serviceUrl:
defaultZone: http://localhost:3000/eureka/ #注册中心服务端的注册地址
instance:
prefer-ip-address: true #使用ip进行注册
instance-id: config-server:6001 #服务注册到注册中心的id
spring:
application:
name: config-server #应用的名称
#码云配置
cloud:
config:
server:
git:
uri: https://gitee.com/biaowww/springcould-config.git
username: [email protected]
password: luo1998biao45
到这里可以测试一下,看配置中心是否可以拿到配置文件的信息
配置中心ip+端口+仓库文件名,访问仓库文件的内容
http://localhost:6001/application-order-dev.yml
注意:config-server的配置文件和eureka-server的配置文件,不能交给仓库管理
以order为例,在order-server导入spring-cloud-starter-config包
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
删除原有的配置文件(改名备份),创建bootstrap.yml文件(配置配置中心地址,配置文件名称,环境)
#指向配置中心,拉取order-server的配置文件
spring:
cloud:
config:
uri: http://localhost:6001 #配置中心的地址
name: application-order #配置文件的名称
profile: dev #环境
测试启动order-server,看端口号,仓库更改配置端口号,再次启动,看更改是否成功