简单使用SpringCloud的fegin和熔断hystrix

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)

②,启动消费者工程,此时已经可以看到效果

③,访问消费者接口,看到如下信息,说明熔断起效果了

④,启动提供者工程,等几秒后,便能正常访问提供者

猜你喜欢

转载自my.oschina.net/u/3574106/blog/1815646