概述
SpringBoot+SpringCloud+Eureka+Feign+Ribbon+Hystrix+Zuul+Mybatis
文章目录
- SpringBoot+SpringCloud+Eureka+Feign+Ribbon+Hystrix+Zuul+Mybatis
- 一、SpringCloud是什么?
- 新建项目spring-cloud-parent做为这个项目统一管理pom的jar,
- 1.Eureka
- 2.服务提供者
- 3.feign(服务消费者)
- 4.ribbon+RestTemplate(服务消费者)
- 5.Zuul
- 总结
本文实例采用springboot、springCloud、eureka、feign/ribbon、hystrix、zuul、mybatis
提示:以下是本篇文章正文内容,下面案例可供参考
一、SpringCloud是什么?
spring-cloud是微服务架构的集成者,将一系列优秀的组件进行了整合。
基于spring-boot构建,以spring-boot方式做到一键启动和部署,能够快速构建微服务系统与第三方对接
整体结构如下:
新建项目spring-cloud-parent做为这个项目统一管理pom的jar,
详细pom如下:
<?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 https://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.0.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-parent</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.Eureka
eureka就是一个服务中心,将所有的可以提供的服务都注册到它这里来管理,调用者需要的时候去注册中心获取,然后在进行调用,方便后续的水平扩展、故障转移
1. 1、新创建一个注册中心springcloud-service-eureka,让其他的服务暴露在注册中心,主要引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
详细pom如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-service-eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-service-eureka</name>
<description>service registry</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.springcloud.service.eureka.SpringcloudServiceEurekaApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
1. 2、此项目只作为一个注册中心,所以不需要过多的代码,只需要启动此项目,在启动类上加上Eureka的注解@EnableEurekaServer表示为注册中心服务,详细代码如下:
package com.example.springcloud.service.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class SpringcloudServiceEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudServiceEurekaApplication.class, args);
}
}
1. 3、配置文件中说明对外的服务名称、暴露服务的ip和端口,在application.yml中加入Eureka配置,详情如下:
#eureka的端口号
spring:
application:
# 对外的服务名
name: springcloud-service-eureka
server:
#分配端口
port: 8001
eureka:
instance:
#eureka的主机
hostname: localhost
client:
#因为此项目本身就是一个服务,是用来别的服务注册到本项目中,不向注册中心注册自己
registerWithEureka: false
fetchRegistry: false
serviceUrl:
#对外提供的服务地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
1. 4、启动项目,可以访问http://localhost:8001查看Eureka,如下图:
注册中心已经创建完成了,下面开始建立服务的提供者,新建springCloud-service-provider,此服务和数据库交互,所以需要引入mysql、mybatis、jdbc等依赖
2.服务提供者
2.1、 在pom中加入Eureka相关依赖,详情如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-service-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-service-provider</name>
<description>eureka provider client</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.springcloud.service.provider.ProviderApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2、 配置服务提供者配置文件,需要配置数据库信息,注册中心配置、mybatis配置等,详情如下:
spring:
application:
name: spring-cloud-service-provider
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
#GMT%2B8代表: 东八区
username: root
password:
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
#注册中心的配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
server:
port: 8084
mybatis:
mapperLocations: classpath:mapper/*.xml
typeAliasesPackage: com.example.springcloud.service.provider.dao
#日志输出mybatis里面的sql
logging:
level:
com.springcloud.muyan.service.dao: debug
2.3、因需要与数据库交互,在resource下创建mapper文件夹,用来存放mapper.xml,并创建名为UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.springcloud.service.provider.dao.UserMapper">
<!-- 获取用户表中所有的信息-->
<select id="getUserList" resultType="com.example.springcloud.service.provider.pojo.UserPojo" >
SELECT * FROM `user`
</select>
<!-- 新增一条数据 -->
<insert id="insert" useGeneratedKeys="false" parameterType="com.example.springcloud.service.provider.pojo.UserPojo" >
INSERT INTO `user` ( `username`, `password`, `age`) VALUES (#{username},#{password},#{age})
</insert>
</mapper>
2.4、 新增实体类
package com.example.springcloud.service.provider.pojo;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:30
**/
@Data
@ToString
public class UserPojo implements Serializable {
//id
private Integer id;
//用户名
private String username;
//密码
private String password;
//年龄
private Integer age;
}
2.5、 新建对应UserMapper.xml接口文件
package com.example.springcloud.service.provider.dao;
import com.example.springcloud.service.provider.pojo.UserPojo;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:36
**/
@Repository
public interface UserMapper {
//获取用户表中所有信息
List<UserPojo> getUserList();
//新增一条数据
int insert(UserPojo userPojo);
}
2.6、 新建service接口及impl实现类
package com.example.springcloud.service.provider.service;
import com.example.springcloud.service.provider.pojo.UserPojo;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:40
**/
public interface ProviderService {
List<UserPojo> getUserList();
void insert(UserPojo userPojo);
}
impl实现类:
package com.example.springcloud.service.provider.service.impl;
import com.example.springcloud.service.provider.dao.UserMapper;
import com.example.springcloud.service.provider.pojo.UserPojo;
import com.example.springcloud.service.provider.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:41
**/
@Service
public class ProviderServiceImpl implements ProviderService {
@Autowired
private UserMapper userMapper;
@Override
public List<UserPojo> getUserList() {
return userMapper.getUser();
}
@Override
@Transactional
public void insert(UserPojo userPojo) {
userMapper.insertUser(userPojo);
}
}
2.7、创建controller
package com.example.springcloud.service.provider.controller;
import com.example.springcloud.service.provider.pojo.UserPojo;
import com.example.springcloud.service.provider.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Random;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:45
**/
@RestController
public class ProviderController {
@Value("${server.port}")
private String port;
@Autowired
private ProviderService providerService;
@RequestMapping(value = "/getPort",method = RequestMethod.GET)
public String getName(@RequestParam(value = "name",required = false) String name){
String result = "请求人:" + name + ",端口是:" + port;
return result;
}
@RequestMapping(value = "/getUserList",method = RequestMethod.GET)
public List<UserPojo> getUserList(){
List<UserPojo> list = providerService.getUserList();
return list;
}
@RequestMapping(value = "/insert")
public String insert(@RequestBody UserPojo userPojo){
String result = "成功";
try {
providerService.insert(userPojo);
}catch (Exception ex){
result = "失败";
ex.printStackTrace();
}
return result;
}
}
2.8、 在启动类上添加注解@EnableEurekaClient、@ComponentScan、@MapperScan注意是EnableEurekaClient不是EnableEurekaServer
package com.example.springcloud.service.provider;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import javax.sql.DataSource;
@SpringBootApplication
@EnableEurekaClient
@ComponentScan(value = "com.example.springcloud.service.provider.*")
@MapperScan(value = {"classpath:config/*.xml","com.example.springcloud.service.provider.dao"})
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
启动服务,查看是否已经将自己注册到注册中心上,http://localhost:8001,注册成功后,访问一下controller查看方法是否正常响应。
3.feign(服务消费者)
feign是一个声明式的伪http客户端,使用非常简单,只需要创建接口并注解,可使用feign注解和JAX-RS注解。支持可插拔的编码器和解码器。feign默认集成了ribbon,并和eureka做了结合,默认实现了负载均衡的效果。
3.1、新建服务消费者springcloud-service-web-feign,详细pom如下
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-service-web-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-service-web-feign</name>
<description>feign test</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<!-- Hystrix 仪表盘 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.springcloud.service.web.feign.SpringcloudServiceWebFeignApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.2、配置文件中配置Eureka信息,及注册服务名
spring:
application:
name: springcloud-service-web-feign
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 10003
#注册中心的配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
# 设置为true表示开启熔断hystrix,设置false表示关闭熔断机制
feign:
hystrix:
enabled: true
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 10000
client:
config:
default:
connectTimeout: 10000 #10s就超时
readTimeout: 10000
#请求处理的超时时间
ribbon:
ReadTimeout: 120000
#请求连接的超时时间
ConnectTimeout: 30000
3.3、创建实体类
package com.example.springcloud.service.provider.pojo;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* @description
* @author: jjb
* @create: 2021-01-25 13:30
**/
@Data
@ToString
public class UserPojo implements Serializable {
//id
private Integer id;
//用户名
private String username;
//密码
private String password;
//年龄
private Integer age;
}
3.4、此处只演示如何进行远程服务调用,其他业务逻辑略,调用远程服务的定义接口声明为feign调用服务方式
package com.example.springcloud.service.web.feign.service;
import com.example.springcloud.service.web.feign.config.FallBackUserPojoClient;
import com.example.springcloud.service.web.feign.config.FeignDisableHystrixConfiguration;
import com.example.springcloud.service.web.feign.pojo.UserPojo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 16:01
**/
@FeignClient(value = "spring-cloud-service-provider",
fallback = FallBackUserPojoClient.class
)
public interface FeignService {
@RequestMapping(value = "/getPort",method = RequestMethod.GET)
public String getName(@RequestParam(value = "name") String name);
@RequestMapping(value = "/getUserList",method = RequestMethod.GET)
public List<UserPojo> getUser();
@RequestMapping("/insert")
public String insertUser(@RequestBody UserPojo userPojo);
}
3.5、这里采用@FeignClient,value是需要调用具体哪个服务,我们这里调用自己写的服务提供者springcloud-service-provider,服务名称都在每个项目的yml文件内,上面的pom文件中我们加入了熔断相关的依赖,在服务的消费者调用服务提供者时,服务挂掉了怎么办,页面请求一直会转圈圈直至超时,视业务情况开启或关闭熔断。可以看到FeignService中加入了fallback=FallBackUserPojoClient.class,这样就告诉系统,如果调用远程服务出现错误导致失败时,执行FallBackUserPojoClient类,当调用任一远程接口失败时,立即给出响应,不需要长时间等待
3.6、因为我们采用Hystrix熔断机制,所以我们需要用服务的降级处理,新建FallBackUserPojoClient类,这个类是给远程接口降级,需要给哪个接口降级就实现哪个接口,这里我们实现FeignService
package com.example.springcloud.service.web.feign.config;
import com.example.springcloud.service.web.feign.pojo.UserPojo;
import com.example.springcloud.service.web.feign.service.FeignService;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 16:07
**/
@Component
public class FallBackUserPojoClient implements FeignService {
@Override
public String getPort(String name) {
return "getPort fail timeout!";
}
@Override
public List<UserPojo> getUserList() {
ArrayList<UserPojo> pojos = new ArrayList<>();
UserPojo userPojo = new UserPojo();
userPojo.setUsername("老王");
pojos.add(userPojo);
return pojos;
}
@Override
public String insert(UserPojo userPojo) {
return "insertUser fail timeout!";
}
}
3.7、对熔断机制我们需要进行监控,pom依赖中已加入仪表盘
package com.example.springcloud.service.web.feign.config;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description
* @author: jjb
* @create: 2021-01-25 16:15
**/
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet hystrixMetricsStreamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(hystrixMetricsStreamServlet);
servletRegistrationBean.setLoadOnStartup(1);
servletRegistrationBean.addUrlMappings("/hystrix.stream");
servletRegistrationBean.setName("HystrixMetricsStreamServlet");
return servletRegistrationBean;
}
}
3.8、创建controller
package com.example.springcloud.service.web.feign.controller;
import com.example.springcloud.service.web.feign.pojo.UserPojo;
import com.example.springcloud.service.web.feign.service.FeignService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-25 16:19
**/
@RestController
public class FeignController {
@Autowired
private FeignService feignService;
/**
* 获取具体调用哪个微服务,如果后台将provider服务启动两个端口,多次调用,会返回不同的微服务端口,模拟负载均衡
* @param name
* @return
*/
@HystrixCommand
@RequestMapping(value = "/getPort",method = RequestMethod.GET)
public String getPort(@RequestParam(value = "name") String name){
return feignService.getPort(name);
}
/**
* 从provider服务中获取所有用户信息
* @return
*/
@HystrixCommand
@RequestMapping(value = "/getUserList",method = RequestMethod.GET)
public List<UserPojo> getUserList(){
return feignService.getUserList();
}
/**
* 向远处服务发送新增一条用户请求
* @param name
* @param password
* @param age
* @return
*/
@RequestMapping(value = "insert",method = RequestMethod.GET)
public String insert(@RequestParam(value = "name") String name,
@RequestParam(value = "password") String password,
@RequestParam(value = "age") int age){
UserPojo userPojo = new UserPojo();
userPojo.setUsername(name);
userPojo.setPassword(password);
userPojo.setAge(age);
System.out.println( "客户端===》新增用户的信息为:username=" + userPojo.getUsername() + ",password=" + userPojo.getPassword() + ",age=" + userPojo.getAge() );
return feignService.insert(userPojo);
}
}
3.9、修改启动类,告诉spring启动的时候需要开启Hystrix相关服务
package com.example.springcloud.service.web.feign;
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;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
//开启熔断器和降级
/**
* 10s失败将服务降级,降级时间是60s,60s内不去调用服务方接口直接熔断,
* 没有特殊场景不推荐开启熔断
*/
@EnableCircuitBreaker
//开启熔断监控
@EnableHystrixDashboard
public class SpringcloudServiceWebFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudServiceWebFeignApplication.class, args);
}
}
模拟集群,我们需要修改服务提供者application.yml文件中的server.port修改为不同的值,再启动一次,启动两个相同而端口不同的服务,接着启动feign调用接口测试调用远程服务,测试一下每次访问是不是返回了不同的端口,实现了访问集群,负载采用的是客户端负载均衡,再调用获取用户信息接口,接口正常继续测试熔断机制,将启用一个提供者服务停掉,在访问是否会被Hystrix熔断。
再来看看熔断监控,访问http:localhost:10003/hystrix,填写title、dashboard,点击Monitor Stream查看具体监控信息,dashboard中填写localhost:10003/hystrix.stream
4.ribbon+RestTemplate(服务消费者)
4.1、新建项目springcloud-service-web-ribbon,pom详情如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-service-web-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-service-web-ribbon</name>
<description>web ribbon</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!--hystrix依赖,主要是用 @HystrixCommand -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<!-- Hystrix 仪表盘 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.springcloud.service.web.ribbon.SpringcloudServiceWebRibbonApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.2、新增配置
spring:
application:
name: springcloud-service-web-ribbon
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: utf-8
servlet:
content-type: text/html
server:
port: 10002
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
4.3、和feign不同的是ribbon需要借助于RestTemplate,只需要使用RestTemplate中最简单的getForEntity发起一个get请求调用服务端接口,可以通过配置@LoadBalanced注解开启客户端负载均衡
package com.example.springcloud.service.web.ribbon.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @description
* @author: jjb
* @create: 2021-01-27 14:04
**/
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4.4、新建实体,业务接口
package com.example.springcloud.service.web.ribbon.pojo;
import lombok.Data;
import lombok.ToString;
/**
* @description
* @author: jjb
* @create: 2021-01-27 14:06
**/
@Data
@ToString
public class UserPojo {
//id
private Integer id;
//用户名
private String username;
//密码
private String password;
//年龄
private Integer age;
}
package com.example.springcloud.service.web.ribbon.service;
import com.example.springcloud.service.web.ribbon.pojo.UserPojo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-27 14:09
**/
@Service
public class RibbonService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "failGetPort")
public String getPort(String name){
return restTemplate.getForObject("http://spring-cloud-service-provider/getPort?name="+name,String.class);
}
@HystrixCommand(fallbackMethod = "fallGetUserList")
public List<UserPojo> getUserList(){
return restTemplate.getForObject("http://spring-cloud-service-provider/getUserList",List.class);
}
public List<UserPojo> fallGetUserList(){
UserPojo userPojo = new UserPojo();
userPojo.setUsername("熔断了~");
ArrayList<UserPojo> list = new ArrayList<>();
list.add(userPojo);
return list;
}
public String failGetPort(String name){
return "调用远程服务springcloud-service-provider失败,熔断getPort方法,name="+name;
}
}
注意:和feign一样,ribbon也加入了熔断机制,注解@HystrixCommand(),fallbackMethod是熔断降级后的处理方法
package com.example.springcloud.service.web.ribbon.controller;
import com.example.springcloud.service.web.ribbon.pojo.UserPojo;
import com.example.springcloud.service.web.ribbon.service.RibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @description
* @author: jjb
* @create: 2021-01-27 14:25
**/
@RestController
public class RibbonController {
@Autowired
private RibbonService ribbonService;
@RequestMapping(value = "/getPort",method = RequestMethod.GET)
public String getPort(@RequestParam("name") String name){
return ribbonService.getPort(name);
}
@RequestMapping(value = "/getUserList",method = RequestMethod.GET)
public List<UserPojo> getUserList(){
return ribbonService.getUserList();
}
}
在启动类上添加注解,完整代码如下:
package com.example.springcloud.service.web.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard
public class SpringcloudServiceWebRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudServiceWebRibbonApplication.class, args);
}
}
启动项目调用ribbon接口查看调用是否正常
5.Zuul
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,新建项目springcloud-service-zuulpom文件:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-service-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-service-zuul</name>
<description>zuul</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.springcloud.service.zuul.SpringcloudServiceZuulApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
5.1、zuul相当于只是起到过滤器作用,没有过多的代码,先修改配置文件
spring:
application:
name: springcloud-service-zuul
server:
port: 10004
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
zuul:
routes:
feign:
path: /feign/**
serviceId: springcloud-service-web-feign
ribbon:
path: /ribbon/**
serviceId: springcloud-service-web-ribbon
这里使用routes,当poth为/feign/** 转发到feign服务, /ribbon/** 转发到ribbon服务,zuul提供了自定义过滤器(ZuulFilter),可以过滤代理请求,提供额外的功能逻辑,例如:鉴权,记录日志等。定义调用失败之后的处理类:
package com.example.springcloud.service.zuul.fallback;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
/**
* @description
* @author: jjb
* @create: 2021-01-27 15:59
**/
@Component
public class WebFeignFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
return "springcloud-service-web-feign";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("message", "网络异常,连接失败!");
return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
package com.example.springcloud.service.zuul.fallback;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
/**
* @description
* @author: jjb
* @create: 2021-01-27 16:04
**/
@Component
public class WebRibbonFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
return "springcloud-service-web-ribbon";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("status", 200);
hashMap.put("message", "网络异常,连接失败!");
return new ByteArrayInputStream(objectMapper.writeValueAsString(hashMap).getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
配置启动类:
package com.example.springcloud.service.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class SpringcloudServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudServiceZuulApplication.class, args);
}
}
启动zuul,访问/feign/**,在访问/ribbon/**
代码下载地址:
https://gitee.com/code_depository/spring-cloud-parent
总结
以上就是今天所演示内容,本文仅简单介绍springCloud的使用,如有不足请指正。
最后
以上就是优秀鞋垫为你收集整理的springCloud实践SpringBoot+SpringCloud+Eureka+Feign+Ribbon+Hystrix+Zuul+Mybatis一、SpringCloud是什么?总结的全部内容,希望文章能够帮你解决springCloud实践SpringBoot+SpringCloud+Eureka+Feign+Ribbon+Hystrix+Zuul+Mybatis一、SpringCloud是什么?总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复