搭建SpringCloud微服务

醉酒当歌 提交于 2019-12-06 14:24:18

建立spring父模块

  • 删除不必要的src目录
  • 父模块中的pom.xml中添加相应的依赖以及插件、远程仓库地址
 1     <!-- 项目的打包类型, 即项目的发布形式, 默认为 jar. 对于聚合项目的父模块来说, 必须指定为 pom -->
 2     <packaging>pom</packaging>
 3 
 4     <name>spring-cloud-home-page</name>
 5     <description>Project For VastHomepage SpringCloud</description>
 6 
 7     <parent>
 8         <groupId>org.springframework.boot</groupId>
 9         <artifactId>spring-boot-starter-parent</artifactId>
10         <version>2.1.4.RELEASE</version>
11     </parent>
12 
13     <properties>
14         <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
15     </properties>
16 
17     <dependencies>
18         <!-- lombok 工具通过在代码编译时期动态的将注解替换为具体的代码,
19         IDEA 需要添加 lombok 插件 -->
20         <dependency>
21             <groupId>org.projectlombok</groupId>
22             <artifactId>lombok</artifactId>
23             <version>1.16.18</version>
24         </dependency>
25         <dependency>
26             <groupId>org.springframework.boot</groupId>
27             <artifactId>spring-boot-starter-test</artifactId>
28             <scope>test</scope>
29         </dependency>
30     </dependencies>
31 
32     <!-- 标识 SpringCloud 的版本 -->
33     <dependencyManagement>
34         <dependencies>
35             <dependency>
36                 <groupId>org.springframework.cloud</groupId>
37                 <artifactId>spring-cloud-dependencies</artifactId>
38                 <version>${spring-cloud.version}</version>
39                 <type>pom</type>
40                 <scope>import</scope>
41             </dependency>
42         </dependencies>
43     </dependencyManagement>
44 
45     <!-- 配置远程仓库 -->
46     <repositories>
47         <repository>
48             <id>spring-milestones</id>
49             <name>Spring Milestones</name>
50             <url>https://repo.spring.io/milestone</url>
51             <snapshots>
52                 <enabled>false</enabled>
53             </snapshots>
54         </repository>
55     </repositories>

 

创建 Eureka注册服务子模块

  • pom.xml中引入必要的依赖以及插件
   <!-- 模块名及描述信息 -->
    <name>spring-cloud-eureka</name>
    <description>Spring Cloud Eureka</description>

    <!-- eureka server: 提供服务发现与服务注册 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

 

  • 资源文件夹(resources)中创建application.yml
spring:
  application:
    name: spring-cloud-eureka

server:
  port: 8000

eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

 

  • 启动类上,加上两个注解@EnableEurekaServer@SpringBootApplication

 

启动

方式一:Teriminal窗口

/** 进入项目目录 */

cd 项目名

/** 将项目打包成jar */

mvn clean package -Dmaven.test.skip=true -U

/** 进入target目录 */

cd target

/** 用jar命令启动项目 */

java -jar 项目名.jar

方式二

直接运行application,启动即可

 

上面是Eureka的单节点启动方式,公司中一般为了防止Eureka单节点故障,下面介绍Eureka的多节点伪集群配置方式

  • 在原项目资源文件夹下创建bootstrap.yml,注释掉application.yml中的配置,因为在springBoot项目中会先加载bootstrap.yml
  • 修改Windows中C:\Windows\System32\drivers\etc路径下的hosts文件
127.0.0.1 server1
127.0.0.1 server2
127.0.0.1 server3

bootstrap.yml:

spring:
  application:
    name: spring-cloud-eureka
  profiles: server1
server:
  port: 8000
eureka:
  instance:
    hostname: server1
    prefer-ip-address: false
  client:
    service-url:
      defaultZone: http://server2:8001/eureka/,http://server3:8002/eureka/

---
spring:
  application:
    name: spring-cloud-eureka
  profiles: server2
server:
  port: 8001
eureka:
  instance:
    hostname: server2
    prefer-ip-address: false
  client:
    service-url:
      defaultZone: http://server1:8000/eureka/,http://server3:8002/eureka/

---
spring:
  application:
    name: spring-cloud-eureka
  profiles: server3
server:
  port: 8002
eureka:
  instance:
    hostname: server3
    prefer-ip-address: false
  client:
    service-url:
      defaultZone: http://server1:8000/eureka/,http://server2:8001/eureka/

 

以上配置完成后,在以上启动方式一的基础上,在启动时需加上一个命令,以表示启动哪个Eureka节点

 

java -jar 项目名.jar --spring.profiles.active=server1 #标识启动Eureka的server1的服务,以此类推

 

 

启动完成后可在浏览器中访问

http://127.0.0.1:8000/

 

父模块中创建zuul网关服务

pom.xml中引入相关依赖、插件

    <!-- 模块名及描述信息 -->
    <name>spring-cloud-zuul</name>
    <description>Spring Cloud Gateway</description>

    <dependencies>
        <!--
            Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
            Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
        -->
        <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>
        <!-- apache 工具类 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

 

资源文件夹中创建application.yml

spring:
  application:
    name: spring-cloud-zuul

server:
  port: 9000

eureka:
  client:
    service-url:
      defaultZone: http://server1:8000/eureka

zuul:
  prefix: /vast
  routes:
    course:
      path: /course/**
      serviceId: spring-cloud-course-service
      strip-prefix: false
    user:
      path: /user/**
      serviceId: spring-cloud-user-service
      strip-prefix: false

 

启动类添加两个注解

@SpringCloudApplication
@EnableZuulProxy

注意:这两个注解和Eureka中启动类中声明的注解是不一样的

 

创建两个过滤类,来计算不同URL请求到响应时所需要的时间

PreFilter.class
package com.vast.zuul.filters;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

@Component
public class PreFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        currentContext.set("startTime", System.currentTimeMillis());
        return null;
    }
}

 

 AccessLogFilter.class

package com.vast.zuul.filters;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Component
public class AccessLogFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        Long startTime = (Long) currentContext.get("startTime");
        HttpServletRequest request = currentContext.getRequest();
        String requestURI = request.getRequestURI();
        Long duration = System.currentTimeMillis() - startTime;
        log.info("uri:{},duration:{}ms", requestURI, duration / 100);
        return null;
    }
}

 

 在父模块下再创建一个子模块服务,作为另外几个服务的父模块(spring-cloud-service)

  • 删掉不需要的src文件夹
  • 在pom.xml中添加
<packaging>pom</packaging>

 

  • 在该模块下,建立公共服务spring-cloud-common

在服务于服务之间,会有一些公共使用的类或方法,避免重复创建以及维护困难,建立公共模块

  • 在pom.xml引入一些依赖
    <dependencies>
        <!-- JSON 处理工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
        <!-- apache 提供的一些工具类 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>
    </dependencies>
  • 在src目录下创建需要用到的公共类

 

在当前父模块(spring-cloud-service)中创建一个课程服务模块(spring-cloud-course-service)

  • 在pom.xml中引入相关依赖以及插件
    <dependencies>
        <!-- 引入 Web 功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
            Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
            Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Java Persistence API, ORM 规范 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- MySQL 驱动, 注意, 这个需要与 MySQL 版本对应 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!-- 通用模块 -->
        <dependency>
            <groupId>com.vast.spring-cloud</groupId>
            <artifactId>spring-cloud-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

 

  • 创建application.yml
server:
  port: 7001
  servlet:
    context-path: /course

spring:
  application:
    name: spring-cloud-course-service
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate.format_sql: true
    open-in-view: false
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    tomcat:
      max-active: 4
      min-idle: 2
      initial-size: 2

eureka:
  client:
    service-url:
      defaultZone: http://server1:8000/eureka/

 

  • 在启动类中添加三个注解

@SpringBootApplication

/** 向Eureka中注册服务  */

@EnableEurekaClient

/** 用JPA来管理数据 */

@EnableJpaAuditing

 

  • 建立实体类
package com.vast.entry;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

@Data/* 表明该实体类中的setter方法是private的,需要通过Builder进行build() **/
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor/** 用来通过注解自动向数据库中插入时间 */
@EntityListeners(AuditingEntityListener.class)
@Table(name = "t_course")
public class CoursePo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    /** 自增 id */
    private Long id;

    @Column(name = "course_name", nullable = false)
    /** 课程名称 */
    private String courseName;

    @Column(name = "course_type", nullable = false)
    /** 课程类型 */
    private Integer courseType;

    @Column(name = "course_icon", nullable = false)
    /** 课程图标 */
    private String courseIcon;

    @Column(name = "course_intro", nullable = false)
    /** 课程介绍 */
    private String courseIntro;

    @CreatedDate
    @Column(name = "create_time")
    /** 创建时间 */
    private Date createTime;
    /** Basic用来表明是列,默认的,不用写也是可以的 */
    @Basic
    @LastModifiedDate
    @Column(name = "update_time")
    /** 更新时间 */
    private Date updateTime;


}

 

  • 创建Dao
package com.vast.dao;

import com.vast.entry.CoursePo;
import org.springframework.data.jpa.repository.JpaRepository;
/** Jpa中有许多已经配置好的方法,以及查询规则,只要按照其指定的规则来即可快速操作数据库中的数据 */
public interface CourseDao extends JpaRepository<CoursePo, Long> {
}

 

  • 课程实现类 CourseImpl
package com.vast.service.impl;

import com.vast.service.ICourseService;
import com.vast.common.entry.Course;
import com.vast.common.entry.RequestContent;
import com.vast.dao.CourseDao;
import com.vast.entry.CoursePo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class CourseImpl implements ICourseService {
    @Autowired
    private CourseDao courseDao;

    @Override
    public Course getCourseById(Long id) {
        Optional<CoursePo> course = courseDao.findById(id);        /** java8特性,Lambda表达式,判断实体类是否为空,防止抛出空指针异常 */
        return builderCoursePo(course.orElseGet(() -> CoursePo.invalid()));
    }

    @Override
    public List<Course> getCourseListByIds(RequestContent requestContent) {
        List<Long> ids = requestContent.getIds();
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<CoursePo> courseList = courseDao.findAllById(ids);        /** java8 特性 */
        return courseList.stream().map(this::builderCoursePo)
                .collect(Collectors.toList());
    }

    /**
     * @param course
     * @return
     * @Description 构造课程信息     * Builder使用方法
     */
    public Course builderCoursePo(CoursePo course) {

        return Course.builder()
                .courseIcon(course.getCourseIcon())
                .courseIntro(course.getCourseIntro())
                .courseName(course.getCourseName())
                .courseType(course.getCourseType() == 0
                        ? "SpringCloud" : "SSM")
                .build();
    }
}

 

测试类

 

 

 

  •  启动类中添加注解

@SpringBootApplication

 

  • 测试类中添加注解

@RunWith(SpringRunner.class)

@SpringBootTest(classes = {TestCourseApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)

 

 

 在当前父模块(spring-cloud-service)中创建一个课程服务模块(spring-cloud-user-service)

  •  在pom.xml中引入相关依赖、插件
    <dependencies>
        <!-- 引入 Web 功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
            Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
            Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入 Feign, 可以以声明的方式调用微服务 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 引入服务容错 Hystrix 的依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!-- Java Persistence API, ORM 规范 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- MySQL 驱动, 注意, 这个需要与 MySQL 版本对应 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!-- 通用模块 -->
        <dependency>
            <groupId>com.vast.spring-cloud</groupId>
            <artifactId>spring-cloud-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

 

  • 在资源文件夹创建application.yml
server:
  port: 7000
  servlet:
    context-path: /user

spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: spring-cloud-user-service
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate.format_sql: true
    open-in-view: false
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    tomcat:
      max-active: 4
      min-idle: 2
      initial-size: 2

eureka:
  client:
    service-url:
      defaultZone: http://server1:8000/eureka/

feign:
  hystrix:
    enabled: true

 

  • 在启动类添加注解

/** 支持Feign调用 */

@EnableFeignClients

/** 支持服务熔断降级 */

@EnableCircuitBreaker

/** 支持JPA */

@EnableJpaAuditing

/** 支持想Eureka注册服务 */

@EnableEurekaClient

@SpringBootApplication

 

  • 实现类UserInfoServiceImpl
package com.vast.service.impl;

import com.vast.client.ICourseFeignClient;
import com.vast.common.entry.Course;
import com.vast.common.entry.RequestContent;
import com.vast.common.entry.User;
import com.vast.dao.UserCourseDao;
import com.vast.dao.UserDao;
import com.vast.entity.UserCourseInfo;
import com.vast.entity.UserInfo;
import com.vast.service.IUserService;
import com.vast.vo.CreateUserRequestVo;
import com.vast.vo.UserCourseInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserInfoServiceImpl implements IUserService {
    private final UserDao userDao;
    private final UserCourseDao userCourseDao;
    private final ICourseFeignClient iCourseFeignClient;

    @Autowired
    public UserInfoServiceImpl(UserDao userDao, UserCourseDao userCourseDao, ICourseFeignClient iCourseFeignClient) {
        this.userDao = userDao;
        this.userCourseDao = userCourseDao;
        this.iCourseFeignClient = iCourseFeignClient;
    }

    @Override
    public User getUserInfoById(Long id) {
        Optional<UserInfo> userInfoById = userDao.findById(id);         /** 判断对象是否为空 */
        if (!userInfoById.isPresent()) {
            return new User().invalidate();
        }
        return builderUserInfo(userInfoById.get());
    }

    @Override
    public User createUserInfo(CreateUserRequestVo createUserRequestVo) {
        /** 判断传的参数是否为空 */
        if (!createUserRequestVo.validate()) {
            return User.invalidate();
        }

        /** 判断该用户在用户表中已存在 */
        UserInfo userInfoByUsername = userDao.findByUsername(createUserRequestVo.getUsername());
        if (null != userInfoByUsername) {
            return User.invalidate();
        }
        UserInfo saveUserInfo = userDao.save(new UserInfo(createUserRequestVo.getUsername(), createUserRequestVo.getEmail()));
        return new User(saveUserInfo.getId(), saveUserInfo.getUsername(), saveUserInfo.getEmail());
    }

    @Override
    public UserCourseInfoVo getUserCourseInfoById(Long id) {
        /** 根据用户id判断是否有该用户 */
        Optional<UserInfo> userInfoById = userDao.findById(id);
        if (!userInfoById.isPresent()) {
            return UserCourseInfoVo.invalidate();
        }
        /** 获取对象 */
        UserInfo userInfo = userInfoById.get();
        User user = new User(userInfo.getId(), userInfo.getUsername(), userInfo.getEmail());

        /** 根据用户id判断用户课程表中是否有该对应的信息 */
        List<UserCourseInfo> allUserCourseInfoByUserId = userCourseDao.findAllByUserId(id);
        if (CollectionUtils.isEmpty(allUserCourseInfoByUserId)) {
            return new UserCourseInfoVo(Collections.emptyList(), user);
        }

        /** 如果用户id在用户表、用户课程表中都存在,则用feign客户端调用课程服务,获取对应
         * 的课程信息,并将用户、课程信息进行返回
         * */
        List<Course> coursesByIds = iCourseFeignClient.getCoursesByIds(new RequestContent(allUserCourseInfoByUserId.stream()
                .map(UserCourseInfo::getCourseId).collect(Collectors.toList())));
        return new UserCourseInfoVo(coursesByIds, user);
    }

    private User builderUserInfo(UserInfo userInfo) {
        return User.builder()
                .id(userInfo.getId())
                .email(userInfo.getEmail())
                .username(userInfo.getUsername())
                .build();
    }
}

 

  • Feign调用客户端
package com.vast.client;

import com.vast.common.entry.Course;
import com.vast.common.entry.RequestContent;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.List;
/** 1.FeignClient表明是Feign调用;  * 2.value表明是调用哪个服务实例;  * 3.fallback是表明熔断时调用哪个类;  * 4.@RequestMapping中的请求方式以及URL和所调用的服务的控制层中的保持一致 */
@FeignClient(value = "spring-cloud-course-service", fallback = CourseHystrixClient.class)
public interface ICourseFeignClient {
    @RequestMapping(value = "/get/course/", method = RequestMethod.GET)
    public Course getCourseInfoById(Long id);

    @RequestMapping(value = "/get/courses", method = RequestMethod.POST)
    public List<Course> getCoursesByIds(@RequestBody RequestContent requestContent);
}

 

  • Hystrix
package com.vast.client;

import com.vast.common.entry.Course;
import com.vast.common.entry.RequestContent;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
/** 1.@Component声明该类是spring的bean实例;  * 2.实现Feign客户端接口方法;  * 3.进行熔断处理; */
@Component
public class CourseHystrixClient implements ICourseFeignClient {
    @Override
    public Course getCourseInfoById(Long id) {
        return Course.inValidEntry();
    }

    @Override
    public List<Course> getCoursesByIds(RequestContent requestContent) {
        return Collections.emptyList();
    }
}

 

测试类

 

  •  启动类中添加注解

@EnableFeignClients(basePackages = {"com.vast"})

@SpringBootApplication

 

  • 测试类中添加注解

@RunWith(SpringRunner.class)

@SpringBootTest(classes = CourseApplication.class)

 

效果图

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!