Spring Cloud

这篇博客介绍了如何使用Spring Cloud构建微服务,包括服务注册与发现(Eureka Server)、服务整合(Feign、负载均衡、Hystrix断路器)以及网关应用(集成Zuul并实现过滤器)。首先,讲解了微服务的基础知识和Spring Cloud在课程查询功能中的应用。接着,详细展示了Eureka Server的配置和Eureka Client的改造过程。然后,通过Feign实现了服务之间的调用,并利用Hystrix添加了断路器保护。最后,介绍了如何集成Zuul作为网关,并创建了记录时间戳的过滤器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

微服务基础

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
微服务特点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
微服务的优缺点

优点:
在这里插入图片描述
缺点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Spring Cloud

在这里插入图片描述

使用 Spring Cloud开发课程查询功能

项目结构:在这里插入图片描述

course-list中:

先导入相关的依赖及插件

<!--导入所需的依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
        </dependency>
    </dependencies>
<!--spring-boot项目必须要的一个插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


在这里插入图片描述
新建启动类CourseListApplication.java:

package com.luo.course;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 项目启动类
 */
@SpringBootApplication
public class CourseListApplication {
    public static void main(String[] args) {
        SpringApplication.run(CourseListApplication.class, args);
    }
}

在这里插入图片描述
新建配置文件application.properties:

server.port=8071
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/course_practice?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai

spring.datasource.username=root
spring.datasource.password=123456
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
mybatis.configuration.map-underscore-to-camel-case=true
spring.application.name=course-list

随后书写控制类,实体类,Mapper接口,service接口以及service接口实现

CourseMapper.java

package com.luo.course.dao;

import com.luo.course.entity.Course;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 课程的Mapper类
 */

@Mapper
@Repository

public interface CourseMapper {

    @Select("SELECT * FROM course WHERE valid=1")
    List<Course> findValidCourses();
}

Course.java(实体类)

package com.luo.course.entity;


import java.io.Serializable;

/**
 * Course实体类
 */
public class Course implements Serializable {

    Integer id;
    Integer sourseId;
    String courseName;
    Integer valid;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }



    public String getCourseName() {
        return courseName;
    }

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public Integer getValid() {
        return valid;
    }

    public void setValid(Integer valid) {
        this.valid = valid;
    }

    public Integer getSourseId() {
        return sourseId;
    }

    public void setSourseId(Integer sourseId) {
        this.sourseId = sourseId;
    }

    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", sourseId=" + sourseId +
                ", courseName='" + courseName + '\'' +
                ", valid=" + valid +
                '}';
    }
}


这里一定要实现Serializable接口以及get和set方法,否则会报错:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;

16:33:49.528 -ERROR 9080 --- [nio-8071-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.luo.course.entity.Course]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.luo.course.entity.Course and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.luo.course.entity.Course and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:313) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1392) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913) ~[jackson-databind-2.9.10.2.jar:2.9.10.2]
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:287) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:291) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar:9.0.30]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]


CourseListController.java

package com.luo.course.controller;

import com.luo.course.entity.Course;
import com.luo.course.service.CourseListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * CourseListController  课程列表控制器
 */
@RestController
public class CourseListController {

    @Autowired
    CourseListService courseListService;

    @GetMapping("/course")
    public List<Course> courseList() {
        return courseListService.getCourseList();
    }
}


CourseListService.java

package com.luo.course.service;


import com.luo.course.entity.Course;

import java.util.List;

/**
 * 课程列表服务
 */
public interface CourseListService {

    List<Course> getCourseList();
}

CourseListServiceImpl.java

package com.luo.course.service.impl;

import com.luo.course.dao.CourseMapper;
import com.luo.course.entity.Course;
import com.luo.course.service.CourseListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CourseListServiceImpl implements CourseListService {
    @Autowired
    CourseMapper courseMapper;

    @Override
    public List<Course> getCourseList() {
        List<Course> courses = courseMapper.findValidCourses();


        return courses;
    }
}

此时有些数据并没有读取到,我们还需要加上驼峰命名转换
在这里插入图片描述
在配置文件中添加驼峰命名转换

mybatis.configuration.map-underscore-to-camel-case=true

course-price中

先导入所需的依赖,书写配置文件,与course-list完全相同,但配置文件中的端口后不能一样。然后类似于前面的,书写根据courseId查找价格的方法
实体类CoursePrice.java:

package com.luo.course.entity;

import java.io.Serializable;

/**
 * CoursePrice的实体类
 */
public class CoursePrice implements Serializable {

    Integer id;
    Integer courseId;
    Integer price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getCourseId() {
        return courseId;
    }

    public void setCourseId(Integer courseId) {
        this.courseId = courseId;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "CoursePrice{" +
                "id=" + id +
                ", courseId=" + courseId +
                ", price=" + price +
                '}';
    }
}

CoursePriceMapper.java

package com.luo.course.dao;

import com.luo.course.entity.CoursePrice;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;


/**
 * 课程价格Mapper类
 */

@Mapper
@Repository
public interface CoursePriceMapper {

        @Select("SELECT * FROM course_price WHERE course_id=#{courseId}")
        CoursePrice findCoursePrice(Integer courseId);



}

CoursePriceService.java

package com.luo.course.service;


import com.luo.course.entity.CoursePrice;

/**
 *  课程价格服务
 */
public interface CoursePriceService {

    CoursePrice getCoursePrice(Integer courseId);
}

CoursePriceServiceImpl.java

package com.luo.course.service.impl;

import com.luo.course.dao.CoursePriceMapper;
import com.luo.course.entity.CoursePrice;
import com.luo.course.service.CoursePriceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


/**
 * 课程价格的实现类
 */
@Service
public class CoursePriceServiceImpl implements CoursePriceService {

    @Autowired
    CoursePriceMapper coursePriceMapper;
    @Override
    public CoursePrice getCoursePrice(Integer courseId) {
        return coursePriceMapper.findCoursePrice(courseId);
    }
}

CoursePriceController.java

package com.luo.course.controller;

import com.luo.course.entity.CoursePrice;
import com.luo.course.service.CoursePriceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 课程价格控制器
 */
@RestController
public class CoursePriceController {

    @Autowired
    CoursePriceService coursePriceService;

    @GetMapping("/price")

    public Integer getCoursePrice(Integer courseId) {
        CoursePrice coursePrice = coursePriceService.getCoursePrice(courseId);
        return coursePrice.getPrice();
    }
}

Eureka Server

服务注册与发现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
启用Eureka的过程:
先导入依赖:

  <!--导入所需的依赖-->
    <dependencies>



<!--        eureka-server的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <!--spring-boot项目必须要的一个插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>




在项目最外层的配置文件中配置spring cloud的版本:

<!--表示spring cloud的版本-->
<dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.SR5</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>

</dependencyManagement>

对Eureka-server进行配置:
application.properties:

spring.application.name=eureka-server
server.port=8070
eureka.instance.hostname=localhost

#fetch-registry:获取注册表。不需要同步其他节点数据
eureka.client.fetch-registry=false

#register-with-eureka:代表是否将自己注册到Eureka Server,默认是true
eureka.client.register-with-eureka=false

#服务所提供的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/


启动类:EurekaServerApplication.java

package com.luo.course;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Eureka的服务端(启动类)
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Eureka Client的改造
将course-list和course-price都作为Eureka-client注册到Eureka-server在这里插入图片描述
porm中添加依赖

<!--        spring cloud的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

配置文件中添加:

eureka.client.service-url.defaultZone=http://localhost:8070/eureka/

服务整合

Feign

声明式、模板式的HTTP客户端
在这里插入图片描述
在这里插入图片描述
步骤:
在这里插入图片描述
导入依赖:

<!--        feign的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>



<!--        自动加入的-->
        <dependency>
            <groupId>com.luo</groupId>
            <artifactId>course-list</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>


在启动类中加入@EnableFeignClients注解
在这里插入图片描述
新建client包,并新建CourseListClient.java接口客户端
在客户端中引入list中控制器的一个方法,
在这里插入图片描述

package com.luo.course.client;


import com.luo.course.entity.Course;
import com.luo.course.entity.CoursePrice;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

/**
 * 课程列表的Feign客户端
 */
@FeignClient("course-list")
public interface CourseListClient {


    @GetMapping("/course")
     List<Course> courseList() ;

}

然后在控制器中新建通过feign获取的方法:
在这里插入图片描述

@GetMapping("/coursesInPrice")

    public List<Course> getCourseListPrice(Integer courseId) {
        List<Course> courses = courseListClient.courseList();
        return courses;
    }

负载均衡

在这里插入图片描述
在这里插入图片描述
在配置文件中配置负载均衡方式
在这里插入图片描述
在配置文件中配置负载均衡:

course-list.ribbon.NFLoadBeanLancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule

在这里插入图片描述

利用Hystrix实现断路器

添加断路器:
先导入相应的依赖:

<!--        添加断路器的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

        </dependency>

然后在配置文件中打开断路器功能:

feign.hystrix.enabled=true

在这里插入图片描述
并在启动类中加入断路器注解:@EnableCircuitBreaker
在这里插入图片描述
然后在调用接口的FeignClient注解中配置断路的类:

@FeignClient(value = "course-list", fallback = CourseListClientHystrix.class)

在这里插入图片描述
并在断路的类中配置短路之后返回的信息:

package com.luo.course.client;

import com.luo.course.entity.Course;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 断路器实现类
 */

@Component
public class CourseListClientHystrix implements
CourseListClient{
    @Override
    public List<Course> courseList() {
        List<Course> defaultCourses = new ArrayList<>();
        Course course = new Course();
        course.setId(1);
        course.setSourseId(1);
        course.setCourseName("默认课程");
        course.setValid(1);
        defaultCourses.add(course);
        return defaultCourses;
    }
}

网关应用:

在这里插入图片描述
在这里插入图片描述

集成Zuul

在这里插入图片描述
新建Zuul项目后,在这里插入图片描述
添加依赖

<dependencies>
    <!--导入Eureka依赖-->

    <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>
</dependencies>
    <!--spring-boot项目必须要的一个插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

配置启动类,并在启动类前面加上注解:`@EnableZuulProxy@SpringCloudApplication

package com.luo.course;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * 网关启动类
 */

@EnableZuulProxy
@SpringCloudApplication
public class ZuulGatewayApplication {


    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }
}

再添加配置文件:

spring.application.name=course-gateway
server.port=8073

logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
mybatis.configuration.map-underscore-to-camel-case=true



eureka.client.service-url.defaultZone=http://localhost:8070/eureka/

zuul.prefix=/luo
zuul.routes.course-list.path=/list/**
zuul.routes.course-list.service-id=course-list


zuul.routes.course-price.path=/price/**
zuul.routes.course-price.service-id=course-price


zuul.prefix=/luo是指在所有网关的地址前添加luo
zuul.routes.course-list.path=/list/** zuul.routes.course-list.service-id=course-list
是将course-list项目链接为list

实现网关过滤器

在这里插入图片描述
书写两个过滤器记录时间戳:
在请求之前的过滤器:PreRequestFilter.java

package com.luo.course.filter;

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 PreRequestFilter 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());
        System.out.println("过滤器已经记录时间");
        return null;
    }
}

在请求之后的过滤器:PostRequestFilter.java

package com.luo.course.filter;

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 PostRequestFilter 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");
        long duration = System.currentTimeMillis() - startTime;
        //获取当前请求的URI
        String requestURI = currentContext.getRequest().getRequestURI();

        System.out.println("uri" + requestURI + ",处理时长:" + duration);
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值