feign+hystrix整合
一 项目准备
- 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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hanergy</groupId>
<artifactId>out</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul-server</name>
<description>zuul project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
<docker.image.prefix>zuul-server</docker.image.prefix>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.10</druid.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 数据库相关jar包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- zipkin链路追踪 包含了sleuth包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!--配置中心客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>zuul-server</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- tag::plugin[] -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.3</version>
<!--将插件绑定在某个phase执行-->
<executions>
<execution>
<id>build-image</id>
<!--将插件绑定在package这个phase上。也就是说,用户只需执行mvn package ,就会自动执行mvn docker:build-->
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<imageName>${docker.image.prefix}</imageName>
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<dockerHost>http://39.106.68.199:2375</dockerHost>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
</project>
- bootstrap.yml
spring:
application:
name: oa
# 配置中心
cloud:
config:
#discovery:
#第一种集成配置中心的方式,通过config的service-id映射 这种方式本地环境无法连接阿里配置中心服务 因为映射的是内网ip 本地无法访问
# 配置中心注册名称 默认去{label}/getway-{profile}.yml文件注册中心命名规则{name}-{profile}.yml /{name}/{profile}/{label}
#service-id: springcloud-config # 配置中心注册名称 默认去{label}节点读取order-{profile}.yml文件
#enabled: true
# 后缀 dev|prod
profile: dev
# dev|master分支,建议使用它区分生产、测试环境
label: dev
# 第二种集成配置中心的方式,这里写配置中心服务的地址信息
uri: http://39.106.68.199:8991
- 配置中心配置文件
eureka:
client:
serviceUrl:
defaultZone: http://39.106.68.199:8761/eureka/,http://39.106.68.199:8762/eureka/,http://39.106.68.199:8763/eureka/
hystrix:
enabled: true
instance:
hostname: ${spring.cloud.client.ip-address}
instance-id: ${spring.cloud.client.ip-address}:8002
prefer-ip-address: true
feign:
client:
config:
default:
connectTimeout: 4000
readTimeout: 4000
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 4000
logging:
level:
com:
hanergy:
activiti:
data: debug
io:
swagger:
models:
parameters:
AbstractSerializableParameter: error
org:
springframework:
boot:
autoconfigure: ERROR
management:
endpoints:
web:
exposure:
include: '*'
mybatis-plus:
configuration:
cache-enabled: false
call-setters-on-nulls: true
map-underscore-to-camel-case: true
global-config:
db-config:
field-strategy: NOT_NULL
id-type: input
logic-delete-value: -1
logic-not-delete-value: 0
refresh: true
mapper-locations: classpath:mybatis/*.xml
typeAliasesPackage: com.hanergy.out.entity
server:
connection-timeout: 5000ms
port: 8002
tomcat:
max-threads: 1000
min-spare-threads: 30
uri-encoding: UTF-8
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
password: ArA8IyYFmQcrlxJP
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://rm-2zezdhr94r3t4et671o.mysql.rds.aliyuncs.com:3306/oa?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=UTC
username: root
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mvc:
static-path-pattern: /static/**
throw-exception-if-no-handler-found: true
redis:
host: r-2zepy3qy5wj310jplipd.redis.rds.aliyuncs.com
open: false
password: X9fMp!guajqOI#Y7
port: 6379
resources:
add-mappings: false
servlet:
multipart:
enabled: true
max-file-size: 100MB
max-request-size: 100MB
sleuth:
sampler:
probability: 0.1
zipkin:
base-url: http://39.106.68.199:9411/
locator:
discovery:
enabled: true
- 启动类添加注解
package com.hanergy.out;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@EnableSwagger2
@EnableFeignClients //feign
@EnableDiscoveryClient
@EnableCircuitBreaker // 熔断器注解
@EnableHystrixDashboard // 断路器Dashboard监控仪表盘
@MapperScan(basePackages = {"com.hanergy.out.dao"})
public class HanergyOutApplication {
public static void main(String[] args) {
SpringApplication.run(HanergyOutApplication.class, args);
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
/**
* corsFilter
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
二、服务间调用
- 调用方:
/**
* name是注册中心注册的名称, 也可以通过url来进行调用,使用url的时候需要配置value
* fallback指定hystrix熔断操作
*/
//@FeignClient(url = "39.106.68.199:8001", value = "12",fallback = FeignClienFallback.class)
@FeignClient(name = "template",fallback = FeignClienFallback.class)
public interface FeignClientService {
@GetMapping("/v1/test/mysql")
public R mysql(@RequestParam("username")String username);
}
熔断实现:
@Service
public class FeignClienFallback implements FeignClientService {
// 这里可以写调用失败处理逻辑
@Override
public R mysql(String username) {
return R.error(-1,"error");
}
}
- 被调用方不用做修改:
package com.hanergy.out.controller;
import com.hanergy.out.entity.SysUser;
import com.hanergy.out.service.ISysUserService;
import com.hanergy.out.utils.R;
import com.netflix.discovery.converters.Auto;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @ClassName TestController
* @Description
* @Auto HANLIDONG
* @Date 2019-7-12 9:51)
*/
@RestController
@RequestMapping("/v1/test")
public class TestController {
Logger log = LoggerFactory.getLogger(TestController.class);
@Autowired
private ISysUserService sysUserService;
@ApiOperation(value="测试",notes="测试信息")
@ApiImplicitParams({
@ApiImplicitParam(name="test",value="测试",required=true,paramType="query")
})
@GetMapping("/test")
public R test(@RequestParam("test")String test){
log.info(test);
return R.ok();
}
@ApiOperation(value="测试",notes="测试信息")
@ApiImplicitParams({
@ApiImplicitParam(name="test",value="测试",required=true,paramType="query")
})
@GetMapping("/mysql")
public R mysql(@RequestParam("username")String username) throws InterruptedException {
log.info(username);
// Thread.sleep(5000);
List<SysUser> sysUsers = sysUserService.findByLikeUserName(username);
return R.ok(1,sysUsers);
}
}