springcloud的记忆和理解
springcloud为微服务的而创建的一种微服务生态系统。随着企业服务的日益庞大,
springboot已经越来越不适应这种环境,服务越多,服务之间的调用和耦合问题等,
都决定了单个或者多个springboot项目的使用上限,因此,springcloud就应运而生。
当然不能说springcloud是一种新的技术,他只是为了构建微服务而兴起的一个微服务的生态系统,
能够一站式的解决微服务架构的各种常见问题,但是其底层还是springboot,无论是eureka,feign,
hystrix等springcloud等组件,都必须构建springboot项目,然后导入对应的依赖,才能生效。
因此,也可以说springcloud就是springboot项目的集合构成的微服务生态系统,
为微服务的管理,解耦,远程调用,安全,分布式等提供了一站式解决方法。
微服务的远程调用:restful+http
看如下代码:
1:消费者代码如下
@Autowired
private RestTemplate restTemplate;
//没有注册中心时,可以直接通过localhost来直接调用 ,8001是服务提供者的端口号
private static final String REST_URL_PREFIX="http://localhost:8001";
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") int id){
Dept dept=restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
System.out.println("消费者向服务提供者拿到消息了"+dept);
return dept;
}
2:服务提供者代码如下:
@GetMapping("/dept/get/{id}")
public Dept queryDept(@PathVariable("id") int id){
Dept dept= deptService.queryDept(id);
if(dept==null){
throw new RuntimeException("该id不正确");
}
logger.info("dept=="+dept);
return dept;
}
由上述代码可知:springcloud就是通过http协议价restful风格进行远程调用,和服务解耦的,消费者和服务提供者的代码相互独立,可以不产生干涉。
加入eureka功能
新建一个springboot modul,
一:导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
二:编写配置文件:注意defaultZone是搭建集群用的,关联其他eureka,本人搭建了三个eureka,
server:
port: 7001
eureka:
instance:
hostname: eureka7001 #服务端的名称
client:
register-with-eureka: false #表示自己为注册中心
fetch-registry: false #如果为false则表示自己为祖册中心
service-url:
defaultZone: http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
三:在主启动类上加入注解
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args){
SpringApplication.run(EurekaServer_7001.class,args);
}
}
四:消费者和服务者需要注册到eurek中,所以他们二人也需要导入eureka依赖,并进行配置
如下:
①在消费者和服务提供方分别导入eureka'的客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
②配置文件
#配置eureka
服务提供者的配置文件
spring:
application:
**name: springcloud-provider-dept** #这个为服务名,eureka上显示的注册服务名称就是这个,记住这个
eureka:
client:
service-url:
defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
instance:
instance-id: springcloud-wangz # 修改eureka上的描述信息
prefer-ip-address: true
消费者的配置文件:
eureka:
client:
register-with-eureka: false #是否要注册到eureka,false表示不用,消费者只是去哪服务,不用把自己注册进去
service-url:
defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,
③:分别在消费者和服务提供者主启动类上 加上注解@EnableEurekaClient,开启eureka功能
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
public static void main(String[] args){
SpringApplication.run(ConsumerApplication.class,args);
}
}
如此eureka就生效了:
当然现在服务提供者已经注册到eureka中了,消费者可以直接去eureka中去查询服务:http访问的网址可以更改为:
@Autowired
private RestTemplate restTemplate;
//没有注册中心时,可以直接通过localhost来直接调用
//private static final String REST_URL_PREFIX="http://localhost:8001";
//现在是从注册中心中提取服务,所以需要改成服务的名称(该名称需要去提供服务的模块去提取,或者去页面上去eureka拷贝)
//springcloud-provider-dept 小写 这个就是上面提供者的spring项目名
private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") int id){
Dept dept=restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
System.out.println("消费者向服务提供者拿到消息了"+dept);
return dept;
}
@RequestMapping("/consumer/dept/add")
public boolean addDept(Dept dept){
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("deptno",6);
paramMap.add("deptname", "dongshizhang");
paramMap.add("db_source", "springcloud");
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",paramMap,Boolean.class);
}
如此eureka的功能就实现了:
第一步:创建属于eureka的modul;淡入对应的依赖,然后再主启动类上加上@EnableEurekaServer注解,表示开启服务功能。
第二步:分别在消费者和提供者modul中导入eureka对应的客户端依赖,在application.yml中进行配置,然后在主启动类上加上:@EnableEurekaClient,开启注册eureka功能(消费者能够去查询服务,提供者可以去注册服务),
第三步:将消费者中的http访地址修改,改为eureka的服务名。
仅此
加入feign功能
feign可以认为是服务内部的网关,但是在笔者看来,其实只是restfui+http进行远程调用的另一种模式:
大家都知道java是面向对象的语言,在企业开发时,服务调用都是面向接口编程(例如controll层调用service),所以一群人就不习惯http+restful远程调用服务,就整出fegin这个功能;
这个功能不难,对比着上面看就好:
一:在整个项目的公共模块中;加入feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
二:在整个项目的公共模块中,创建接口类,接口的内的抽象方法为服务提供者controller层方法(方法名参数必须保持一致)如下,接口上加上注解@FeignClien,里面的参数为服务提供者的名字(大写,若不清楚可以观看上面内容中服务提供者的配置文件)
@Component
@FeignClient(value = “SPRINGCLOUD-PROVIDER-DEPT”)
public interface DeptService {
@GetMapping("/dept/get/{id}")
Dept queryDept(@PathVariable("id") int id);
}
然后主启动类上加上注解@EnableFeignClients
(basePackages = “com.wangz.servicefeign”) basepacket为:公共模块中接口所在包(上面接口),必须要能够扫描到
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.wangz.servicefeign")
@ComponentScan(value = {"com.wangz.servicefeign","com.wangz.config","com.wangz.controller"})
/**
* 在微服务启东时会自动加载Ribbon负载均衡策略类(该类可以自定义,最好放在和启动类不同的包下,以便识别
* 否则会被Ribbin共享)
* name:需要负载均衡的服务 configuration:负载均衡的策略
*
* 注:使用该注解一般为加载自定义的负载均衡策略,若Ribbin类中已经有则不需要该注解,直接
* 在ConfigBean类中配置一个负载均衡策略的bean就好
*/
//@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration= IRule.class)
public class FeignConsumerApplication {
public static void main(String[] args){
SpringApplication.run(FeignConsumerApplication.class,args);
}
}
做好这些之后,就差不多了,之后消费者就可以通过调用上面的接口进行服务调用(也就是面向接口编程)
消费者调用的代码再次更改为:
@Autowired
private DeptService deptService: #注入的是公共模块中书写的接口类
/**
* 加入eureka后默认返回xml格式,若想返回json格式,则需要添加produces 指定返回格式
*/
@RequestMapping(value = "/consumerfeign/dept/get/{id}",produces = "application/json; charset=UTF-8")
public Dept get(@PathVariable("id") int id){
System.out.println("dddddddddddd");
Dept dept=deptService.queryDept(id);
System.out.println(dept);
return dept;
}
加入ribbin功能
ribbin的主要功能就是负载均衡:这个功能的使用可以说是可最简单的:
第一:导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
修改配置类:在配置的restTemplate上加上@LoadBalanced 注解即可
(RestTemplate,从最开始就最好交给spring容器管理,使用负载均衡功能加入一个注解就好)
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //配置负载均衡
public RestTemplate getReatTemplate(){
return new RestTemplate();
}
}
如此ribbin功能实现完毕简单,当然默认的如在均衡是随机访问
若想想其他的负载均衡策略,再加一个bean即可:
@Bean
@LoadBalanced //配置负载均衡
public RestTemplate getReatTemplate(){
return new RestTemplate();
}
@Bean
public IRule myIRule(){
return new RandomRule(); //这里new了什么策略,上面的@LoadBalanced就会采用那种策略。当然可以自定义
}
}
=========================================================================================
当然也可以在主启动类上加注解
/**
* 在微服务启东时会自动加载Ribbon负载均衡策略类(该类可以自定义,最好放在和启动类不同的包下,以便识别
* 否则会被Ribbin共享)
* name:需要负载均衡的服务 configuration:负载均衡的策略
*
* 注:使用该注解一般为加载自定义的负载均衡策略,若Ribbin类中已经有则不需要该注解,直接
* 在ConfigBean类中配置一个负载均衡策略的bean就好
*/
//@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration= IRule.class)
public class FeignConsumerApplication {
public static void main(String[] args){
SpringApplication.run(FeignConsumerApplication.class,args);
}
}
加入hystrix功能(熔断降级)
熔断:断的是提供服务的一方;当调用的服务链比较长或者服务链从中断裂时,客户端或者消费端就会返回异常,这通常是我们不愿意看到的,因此提出了熔断一说,给每个服务都提供一个备用方案,那个服务出现问题时,就讲备份服务返回给客户端。
降级:降得是消费者(客户端一方),当提供服务的服务器出现问题时,或者一访问服务就出错,或者其他服务在某一时间需要大量的系统资源时,将本服务暂时关闭,这种情况下采用降级最好,降级就是在消费者方提供一个备份方法,当服务端不能访问时,直接在客户端就调用备份方法(俗称降级服务),不占用服务端的任何cpu资源。
一:服务端熔断
第一步导入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
第二步:在方法上加上注解@HystrixCommand,并准备备用方法
@GetMapping("/dept/get/{id}")
@HystrixCommand(fallbackMethod = "HystrixqueryDept")
public Dept queryDept(@PathVariable("id") int id){
Dept dept= deptService.queryDept(id);
if(dept==null){
throw new RuntimeException("该id不正确");
}
logger.info("dept=="+dept);
return dept;
}
//备用方法
public Dept HystrixqueryDept(@PathVariable("id") int id){
Dept dept=new Dept(id,"id为"+id+"的部门不存在","数据库中也没有");
return dept;
}
第三步:在主启动类上加上注解@EnableCircuitBreaker,开启熔断功能。
二:客户端降级
还记得在feign功能的内容中,创建的一个接口类,该接口类中创建的抽象方法,都是服务提供方控制层的方法吧
在公共模块中导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
二:书写上面接口类的实现类:实现FallbackFactory接口,重写方法
@Component
public class ServicefeginHystrix implements FallbackFactory {
@Override
public Object create(Throwable throwable) {
return new DeptService() {
@Override
public Dept queryDept(int id) {
return new Dept(-1,"服务已经暂停开启,请关注官网通告");
}
};
}
}
三;在接口类上加上注解:value:服务名称 fallbackFactory:实现的降级类
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory=ServicefeginHystrix.class)
public interface DeptService {
@GetMapping("/dept/get/{id}")
Dept queryDept(@PathVariable("id") int id);
}
hystrix功能就此完结
zuul功能添加
创建新moudl:
第一步:导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
第二步:在主启动类中加上注解
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class SpringcloudZuul {
public static void main(String[] args) {
SpringApplication.run(SpringcloudZuul.class,args);
}
}
zuul也是需要注册到eureka中的
第三步:书写配置
spring:
application:
name: springcloud-wanngz-zuul
eureka:
client:
service-url:
defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
instance:
instance-id: springcloud-zuul # 修改eureka上的描述信息
prefer-ip-address: true
info:
app.name: wangz-springcloud
company-name: blog.wangz.log
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /mydept/**
ignored-services: "*" #springcloud-provider-dept #不能在使用这个路径访问了
prefix: /wangz #设置公共的前缀
zuul搞定