SpringCloud中fegin的使用是非常优雅的,被大多数面向接口编程的程序员喜欢,而且熔断(hystrix)则能在服务不可达时快速给客户端一个默认响应。可以说是很不错的机制,今天我们就来了解一下这两个。
1,准备
①,用idea建立一个空工程
②,添加一个pom类型的父模块
③,给父工程添加子模块即可
④,结构如下
⑤,eclipse就更简单了,直接建立一个pom类型的父工程,右键父工程给其添加子模块即可
2,父工程配置
①,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--这里一定要是pom,不然公共的api模块会无法install-->
<packaging>pom</packaging>
<name>spc-parent</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!-- 父类工程管理机制 -->
<dependencyManagement>
<dependencies>
<!--springcloud 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springboot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.12.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory><!-- 这个路径下的文件运行访问 -->
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit><!-- 访问被$包围的值 -->
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
</project>
3,api模块
①,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--保留名字-->
<artifactId>api</artifactId>
<!--父工程-->
<parent>
<groupId>com.example</groupId>
<artifactId>spc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies><!-- 依赖fegin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
</dependencies>
</project>
②,用到的pojo
import java.util.Date;
public class Ticket {
private Integer id;
private String name;
private Date buyDate;
}
③,定义接口
import com.example.api.bean.Ticket;
import com.example.api.factory.TickClientServiceFallbackFactory;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
//必须指定服务名,指定熔断统一处理类
@FeignClient(value = "ticket-provider",fallbackFactory =TickClientServiceFallbackFactory.class)
public interface TicketService {
// 以下为暴露的服务,与提供者的映射路径一致
@RequestMapping(value = "/ticket/add", method = RequestMethod.POST)
public boolean add(Ticket ticket);
@RequestMapping(value = "/ticket/get/{id}", method = RequestMethod.GET)
public Ticket get(@PathVariable("id") Long id);
@RequestMapping(value = "/ticket/list", method = RequestMethod.GET)
public List<Ticket> list();
}
④,熔断处理类
import com.example.api.bean.Ticket;
import com.example.api.service.TicketService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
//加入到ioc容器
@Component
public class TickClientServiceFallbackFactory implements FallbackFactory<TicketService> {
@Override
public TicketService create(Throwable cause) {
// 通过匿名内部类的方式,如果出错默认结果
return new TicketService() {
@Override
public boolean add(Ticket ticket) {
System.out.println("添加失败^_^");
return false;
}
@Override
public Ticket get(Long id) {
Ticket ticket = new Ticket();
ticket.setId(1);
ticket.setBuyDate(new Date());
ticket.setName("请稍后重试");
return ticket;
}
@Override
public List<Ticket> list() {
return null;
}
};
}
}
4,消费者配置
①,pom.xml
<artifactId>customer</artifactId>
<parent>
<groupId>com.example</groupId>
<artifactId>spc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Feign相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- eureka相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
②,application.properties
server.port=8201
spring.application.name=ticket-customer-fegin
eureka.instance.prefer-ip-address=true
#注册地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#开启熔断
feign.hystrix.enabled=true
③,主配置类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
//注册到eureka
@EnableEurekaClient
@SpringBootApplication
//指定fegin扫描的包,需要即扫描api工程中熔断配置类
@EnableFeignClients(basePackages= {"com.example.api"})
//需要扫描api工程及本工程注册的bean
@ComponentScan("com.example")
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
④,controller层代码编写
import com.example.api.bean.Ticket;
import com.example.api.service.TicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class CustomerController {
@Autowired
private TicketService ticketService;
@RequestMapping(value = "/fegin/add")
public boolean add(Ticket ticket) {
return ticketService.add(ticket);
}
@RequestMapping(value = "/fegin/get/{id}")
public Ticket get(@PathVariable("id") Long id) {
return ticketService.get(id);
}
@RequestMapping(value = "/fegin/list")
public List<Ticket> list() {
return ticketService.list();
}
}
5,提供者配置
①,pom.xml
<artifactId>provider</artifactId>
<parent>
<groupId>com.example</groupId>
<artifactId>spc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 将微服务provider侧注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
②,application.properties
server.port=8002
#服务名
spring.application.name=ticket-provider
#使用ip进行注册
eureka.instance.prefer-ip-address=true
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
③,主配置类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient //启动后注册到eureka
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
④,controller层代码
import com.example.api.bean.Ticket;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@RestController
public class TicketController {
@RequestMapping(value = "/ticket/add", method = RequestMethod.POST)
public boolean add(Ticket ticket) {
System.out.println("添加成功");
return true;
}
@RequestMapping(value = "/ticket/get/{id}", method = RequestMethod.GET)
public Ticket get(@PathVariable("id")Long id) {
Ticket ticket = new Ticket();
ticket.setId(1);
ticket.setBuyDate(new Date());
ticket.setName("《男儿当自强》");
return ticket;
}
@RequestMapping(value = "/ticket/list", method = RequestMethod.GET)
public List<Ticket> list() {
System.out.println("找到了好多数据。。。。");
return Collections.emptyList();
}
}
6,测试
①,启动注册工程(eureka)
②,启动消费者工程,此时已经可以看到效果
③,访问消费者接口,看到如下信息,说明熔断起效果了
④,启动提供者工程,等几秒后,便能正常访问提供者