Spring Cloud Microservices Практические подробные примечания

задняя часть сервер Spring RabbitMQ

Эта статья представляет собой заметку из видеоконспекта некой сети курсов по микросервисам SpringCloud, в которой участвуют

  1. Конфигурация сервера Eureka и клиента Eureka
  2. Высокая доступность сервера Eureka
  3. Два способа межсервисного взаимодействия: RestTemplate и Feign
  4. Установка и использование RabbitMQ
  5. Использование центра конфигурации
  6. Использование Spring Cloud Stream
  7. Различные варианты использования сервисного шлюза Zuul

Потому что это тест на ноты, напишите немного случайно, Bigwigs прости меня ~

Большинство технологий, упомянутых в этой статье, будут использоваться в одном из моих проектов с открытым исходным кодом.Основная часть бизнес-логики этого проекта в основном написана, и необходимы только проверка авторизации, настройка шлюза и пост-оптимизация. кому интересно может посмотреть..

адрес проекта:GitHub.com/cache Cats/ из…


1. О командной строке

Запустите проект SpringBoot

java -jar test.jar

Запустите проект SpringBoot и укажите порт

java -jar -Dserver.port=8899 test.jar

Начните проект Sprilboot и укажите фон для запуска

nohup java -jar test.jar > /dev/null 2>&1 &

Посмотреть прогресс

ps -ef | grep eureka

убить процесс

kill -9 进程号

Установите проект локально в локальный репозиторий maven.

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

2. Сервер Эврика

2.1 Новый

Выберите CloudDiscovery -> Eureka Server.

Обратите внимание на версию SpringBoot

2.2 Конфигурация

Аннотировать приложение класса запуска

@EnableEurekaServer

в файле конфигурацииapplication.ymlрегистрационная служба

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/

Запустите проект и введите адрес в браузереhttp://localhost:8080Вы можете увидеть, что проект запускается нормально и зарегистрироваться самостоятельно.

ApplicationNameдаUNKNOWN, если вы хотите изменить имя приложения, перейдите кapplication.ymlВыполните следующую настройку

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
spring:
  application:
    name: eureka

Перезапустите проект, просмотрите его в браузере, имя отображается корректно

Если вы не хотите, чтобы реестр отображался в списке регистрации, настройтеregister-with-eureka: false

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/   #配置默认注册地址
    register-with-eureka: false  #不让该服务显示在应用列表中
spring:
  application:
    name: eureka  #配置应用名字

3. Клиент Эврика

3.1 Новый проект

Выберите CloudDiscovery -> Eureka Discovery.

Обратите внимание, что версии SpringBoot и SpringCloud такие же, как и у сервера

3.2 Конфигурация

  1. ВходApplicationдобавить аннотацию@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}
  1. Настроить адрес сервера
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: client
  1. Настройте адрес ссылки. После настройки адрес браузера станетhttp://clientname:8080/
eureka:
  instance:
    hostname: clientName
  1. Если вы часто перезапускаете клиентскую службу, у вас будет следующее предупреждение

Это механизм самозащиты SpringCloud, то есть независимо от того, онлайн сервис или нет, он считается онлайн. В среде разработки эту функцию можно отключить для удобства отладки, обратите внимание, что рабочая среда должна быть включена.

на сервереapplicaitono.ymlВыполните следующую настройку в

eureka:
  server:
    enable-self-preservation: false

4. Высокая доступность сервера Eureka

В настоящее время клиент зарегистрирован на сервере Eureka, что делать, если сервер зависает?

Несколько серверов Eureka могут быть запущены и зарегистрированы друг с другом.

Здесь презентация запускает три сервера EUREKA для регистрации друг друга и регистрации клиента на этих трех серверах соответственно.

настроить сервер

Старт на трех портах 8761, 8762, 8763 соответственноEurekaApplication,EurekaApplication2,EurekaApplication3три службы, в трех службахapplicaiton.ymlАдреса двух других сервисов настраиваются отдельно.

какEurekaApplicationдостойныйhttp://localhost:8762/eureka/,http://localhost:8763/eureka/,

EurekaApplication2достойныйhttp://localhost:8761/eureka/,http://localhost:8763/eureka/,

EurekaApplication3достойныйhttp://localhost:8761/eureka/,http://localhost:8762/eureka/,

EurekaApplicationизapplicaiton.ymlследующее:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/

Это связывает три службы друг с другом.

настроить клиент

Затем в клиентеapplicaiton.ymlСопоставьте все три служебных адреса в

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/

ПроверятьEurekaApplication, найдено зарегистрированным на 8762 и 8763. Пока один из трех серверов жив, сервис не зависнет.

5. Связь между приложениями

Существует два основных типа связи между приложениями:

HTTP означает: SpringCloud

RPC расшифровывается как: Дуббо

Два спокойных метода вызова между сервисами в SpringCloud

  • RestTemplate
  • Feign

5.1 Метод RestTemplate

Существует три метода вызова RestTemplate, которые описаны ниже.

В приложении для записи данных для предоставления контроллера открытых интерфейсов, называемыхServerControllerБар

@RestController
@RequestMapping("/product")
public class ServerController {

    @GetMapping("/msg")
    public String getMsg(){
        return "I am product msg";
    }
}

Затем напишите контроллер в приложении, которое должно получать данные, называемоеClientController

5.1.1 Метод 1

Использовать напрямуюRestTemplateВручную напишите URL-адрес, который предоставляет данные

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @GetMapping("/getmsg")
    public String getMsg(){
        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.getForObject("http://localhost:8080/product/msg", String.class);
        log.info("result={}", result);
        return result;
    }
}

5.1.2 Метод 2

Вместо того, чтобы вручную вводить URL-адрес, используйтеLoadBalancerClientДинамически получить по имени приложения, а затем использоватьRestTemplate.

loadBalancerClient.choose("product");этоproductэто идентификатор приложения, которое предоставило данные

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    LoadBalancerClient loadBalancerClient;

    @GetMapping("/getmsg")
    public String getMsg(){
        ServiceInstance serviceInstance = loadBalancerClient.choose("product");
        String url = String.format("http://%s:%s/product/msg", serviceInstance.getHost(), serviceInstance.getPort());
        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.getForObject(url, String.class);
        return result;
    }
}

5.1.3 Метод 3

использовать@LoadBalancedаннотация

новыйRestTemplateConfigсвоего рода

@Component
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

затем вClientControllerиспользуется в.

restTemplate.getForObject("http://product/product/msg", String.class);два в адресеproduct, первое — это имя приложения, а второе — адрес API. если адрес API/abc, тогда URL-адресhttp://product/abc

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    RestTemplate restTemplate;
    
    @GetMapping("/getmsg")
    public String getMsg(){
        String result = restTemplate.getForObject("http://product/product/msg", String.class);
        return result;
    }
}

5.2 Метод действительности

Есть несколько шагов использования FeiGn

Шаг 1. Внедрение зависимостей

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Уведомление

Обратите внимание на проблему здесь Зависимости, упомянутые в некоторых видео и статьях,spring-cloud-starter-feign, я тоже это приводил в начале, но жизнь и смерть не привносишь. Затем перейдите в репозиторий mavenmvnrepository.com/смотри, ищиspring-cloud-starter-feignСмотри, там написано:

Spring Cloud Starter Feign (deprecated, please use spring-cloud-starter-openfeign)

Сказатьspring-cloud-starter-feignУстарело, пожалуйста, используйтеspring-cloud-starter-openfeign.

Версия SpringCloud, которую я использую, относительно высока и может не поддерживаться.spring-cloud-starter-feign.

Шаг 2. Настройте аннотацию @EnableFeignClients

Конфигурация в начальном классе программы@EnableFeignClientsаннотация

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

не могу найти@EnableFeignClientsЕсли да, проверьте, правильно ли процитированы зависимости и верна ли версия.

Шаг 3: Создайте инкапсулированный интерфейс

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "product")
@Component
public interface ProductClient {

    @GetMapping("/product/msg")
    String getMsg();
}

добавить в интерфейс@FeignClientПримечания в скобкахname = "product"заявляет, что приложение с именемproductПриложение находит данные (имя приложения не чувствительно к регистру).

@GetMapping("/product/msg")Обратите внимание на метод запроса и путь.

такgetMsg()метод означает запросproductAPI в приложении есть/product/msgНить.

Шаг 4: звонок

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    ProductClient productClient;

    @GetMapping("/getmsg")
    public String getMsg(){
        return productClient.getMsg();
    }
}

Внедрить созданный на третьем шагеProductClient, а затем напрямую вызвать метод, определенный в интерфейсе.

я ввожу здесьProductClientРедактор сообщит об ошибке, но на компиляцию это не повлияет.

Could not autowire. No beans of 'ProductClient' type found

Это не радует глазProductClientдобавил@Componentаннотация.

Наконец, резюмируйте Feign:

  • Декларативный клиент REST (псевдо-RPC)
  • аннотации на основе интерфейса

6. Установите RabbitMQ

В этой статье для установки RabbitMQ используется Docker, см. руководство по Docker.здесь

Откройте официальную страницу загрузки RabbitMQ.woohoo.rabbitcurrent.com/download.contract… Docker

нажмитеDocker imageСсылка на страницу с подробностями

Вы можете видеть, что последняя версия3.7.7,копировать3.7.7-management, введите следующий код в командной строке и запустите

docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.7-management

Используйте docker ps, чтобы увидеть наши запущенные контейнеры

Solo-mac:~ solo$ docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                                                                        NAMES
345859e88ead        rabbitmq:3.7.7-management   "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp   goofy_volhard

Вход через браузерhttp://localhost:15672Open Rabbitmq, в первый раз потеряет имя пользователя и пароль, имя пользователя и парольguest, войдите в интерфейс управления после ввода

На этом установка RabbitMQ завершена.

7. Центр конфигурации

7.1 Конфигурация сервера центра конфигурации

  1. Новая конфигурация проекта

    勾选 Cloud Config -> Config Server 和 Cloud Discovery -> Eureka Discovery
    
  2. Добавить аннотацию к классу запуска

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableConfigServer
    public class ConfigApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConfigApplication.class, args);
        }
    }
    
  3. Создайте новый проект на github или в облаке кода,orderПроектapplication.ymlФайл конфигурации загружен для тестирования.

  4. настроить проектapplication.ymlдокумент

    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8081
    spring:
      application:
        name: config
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/xxxxxxx
              username: xxxxxx
              password: xxxxxx
              basedir: xxxxxx  #本地的路径
    

    uri — адрес склада, логин и пароль — логин и пароль склада

  5. После завершения настройки запустите проект, вы увидите, что проект зарегистрирован в центре регистрации, и получите доступ к нему в браузере.http://localhost:8081/order-a.ymlТакже прочитайте файл конфигурации на git в обычном режиме.

    Суффикс ввода адреса доступа — «/order-a.yml», который объясняется здесь.

    /{name}-{profiles}.yml
    /{label}/{name}-{profiles}.yml
    
    name: 服务名,这里是 order
    profiles 环境
    label 分支(branch) 不写的话默认是 master 分支
    

7.2 Конфигурация клиента центра конфигурации

Использовать элемент заказа в качестве клиента

  1. в порядке серверного модуляpom.xmlдобавить в файлconfig-clientполагаться
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
  1. будетapplication.ymlпереименовать вbootstrap.yml

  2. настроитьbootstrap.yml

    spring:
      application:
        name: order
      cloud:
        config:
          discovery:
            enabled: true
            service-id: config  #配置中心server的应用名
          profile: dev
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    

После завершения настройки запустите проект, и он сможет нормально работать.

Уведомление:

  1. Не забудьте переименовать файл конфигурацииbootstrap.yml
  2. Настройте URL-адрес службы eureka в локальном файле конфигурации вместо того, чтобы читать его из config, потому что, если номер порта eureka не является значением по умолчанию 8761, он не будет найден.
  3. Если есть gitorder.yml,order-dev.yml, сконфигурированный сorder-dev.yml, он также будет загружаться по умолчанию при загрузкеorder.ymlи объедините два файла. Используя эту функцию, можноorder.ymlЗапишите публичную конфигурацию в .

7.3 Конфигурация автоматического обновления Spring Cloud Bus

7.3.1 Добавить зависимость Spring Cloud Bus в проект конфигурации

Добавить зависимость от Spring Cloud BUS в проекте конфигурации

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

Запустите проект и просмотрите его в консоли RabbitMQ: есть соединение, указывающее на то, что конфигурация прошла успешно.

7.3.2 Добавление зависимости Spring Cloud Bus в проект заказа

Добавьте зависимости к серверному модулю порядка, как указано выше.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

Запускаем и смотрим RabbitMQ, там два подключения

7.3.3 Настройка автоматического обновления

Конфигурация Конфигурация элементовapplication.ymlфайл, будетbus-refreshоткрытый интерфейс

management:
  endpoints:
    web:
      exposure:
        include: "*"

Создайте новый контроллер, чтобы прочитать поле env в удаленной конфигурации.

Метод value принимает конфигурацию
@RestController
@RequestMapping("/env")
@RefreshScope
public class EnvController {

    @Value("${env}")
    private String env;

    @GetMapping("/print")
    public String print(){
        return env;
    }
}

Обязательно добавьте@RefreshScopeОбратите внимание, в противном случае конфигурация не будет обновляться автоматически.

Запустите оба проекта снова, посетитеhttp://localhost:8899/env/printРезультатом является значение ENV, настроенное на git.

Измените значение env на git, отправьте запрос на публикациюhttp://127.0.0.1:8081/actuator/bus-refreshОчистить очередь сообщений, затем очиститьhttp://localhost:8899/env/printВы увидите, что проект не перезапущен, но значение env изменилось.

Конфигурация префикса

git конфигурация

env: dev5

girl:
  name: lili
  age: 18

Новый классGirlConfig

@Data
@Component
@ConfigurationProperties("girl")
@RefreshScope
public class GirlConfig {

    private String name;

    private Integer age;
}

новыйGirlController

@RestController
public class GirlController {

    @Autowired
    GirlConfig girlConfig;

    @GetMapping("girl/print")
    public String print(){
        return "name= " + girlConfig.getName() + ", age= " + girlConfig.getAge();
    }
}

ввод в браузереhttp://localhost:8899/girl/print, получил ответname= lili, age= 18.

Измените конфигурацию git, как указано выше, и отправьте почтовый запрос.http://127.0.0.1:8081/actuator/bus-refreshОбновите очередь сообщений, и вы увидите, что результат также изменился.

Если требуетсяhttp://127.0.0.1:8081/actuator/bus-refreshВозвращаемое значение равно 500, то есть шина хорошо поработала. Последняя возможная причина заключается в том, что версия,SpringBootИзменить версию2.0.0.BUILD-SNAPSHOT,SpringCloudверсия изменена наFinchley.BUILD-SNAPSHOTВсе должно быть в порядке.

Восемь, основное использование RabbitMQ

Демонстрация заказа проекта

Сначала настройте в файле конфигурацииrabbitmqИнформация. Эти конфигурации могут быть размещены на удаленном git

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

8.1 Основное использование

Существует три основных способа получения сообщений.

Способ 1: очередь должна быть объявлена ​​заранее

  1. Сначала создайте очередь в консоли RabbitMQ.myQueue
  2. Снова создайте приемник сообщений и распечатайте его на консоли после получения сообщения.
/**
 * RabbitMQ 消息接收者
 */
@Slf4j
@Component
public class MqReceiver {

    @RabbitListener(queues = "myQueue")
    public void process(String msg){
        log.info("reveicer: " + msg);
    }
}
  1. Создайте отправителя сообщения, напишите метод в тестовом классе для простоты

    /**
     * RabbitMQ 消息发送方
     */
    @Component
    public class RabbitMQTest extends OrderApplicationTests {
    
        @Autowired
        AmqpTemplate amqpTemplate;
    
        @Test
        public void test1(){
            amqpTemplate.convertAndSend("myQueue", "now " + new Date());
        }
    }
    

Запуск теста, консоль успешно распечатает принятое сообщение.

Способ 2: автоматическое создание очереди

Во-первых, очередь, созданная первым методомmyQueueУдалить, отправитель остается без изменений, изменить получателя

@RabbitListener(queuesToDeclare = @Queue("myQueue"))
public void process(String msg){
	log.info("reveicer: " + msg);
}

использоватьqueuesToDeclareОчередь создается автоматически.

Способ 3: автоматически создать очередь и привязать очередь и обмен

Сначала первая очередьmyQueueУдалить, отправитель остается без изменений, изменить получателя

@RabbitListener(bindings = @QueueBinding(
        value = @Queue("myQueue"),
        exchange = @Exchange("myExchange")
))
public void process(String msg){
    log.info("reveicer: " + msg);
}

8.2 Группировка сообщений

Предположим, что служба заказов состоит из двух групп: цифровых поставщиков и поставщиков фруктов. После размещения заказа компьютерный заказ будет отправлен цифровому поставщику, а заказ фруктов будет отправлен поставщику фруктов. Каждый из двух провайдеров получает свое собственное сообщение.

получатель

    /**
     * 数码供应商接收消息
     * @param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange("myOrder"),
            key = "computer",
            value = @Queue("computerOrder")
    ))
    public void processComputer(String msg){
        log.info("computerOrder reveicer: " + msg);
    }

    /**
     * 水果供应商接收消息
     * @param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange("myOrder"),
            key = "fruit",
            value = @Queue("fruitOrder")
    ))
    public void processFruit(String msg){
        log.info("fruitOrder reveicer: " + msg);
    }

отправитель сообщения

@Test
public void send(){
	amqpTemplate.convertAndSend("myOrder", "computer", "now " + new Date());
}

Присланный сюда заказ - это компьютер,convertAndSend()Три параметра по очередиexchange, routingKey, message

Только после отправки сообщенияcomputerOrderсообщение доставлено.

Глядя на консоль RabbitMQ, вы можете четко увидеть взаимосвязь между обменом и очередью.

Девять, весенний облачный поток

Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.

Промежуточное программное обеспечение сообщений, которое в настоящее время поддерживается Spring Cloud Stream, толькоRabbitMQиKafka

9.1 Процедуры

Объединить нижеRabbitMQПродемонстрируйте использование Spring Cloud Stream

  1. импортировать зависимости

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId> 
    </dependency>
    
  2. Настройте RabbitMQ, как в предыдущем разделе.

    spring:
      rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest
    
  3. Создать интерфейс StreamClient

    import org.springframework.cloud.stream.annotation.Input;
    import org.springframework.cloud.stream.annotation.Output;
    import org.springframework.messaging.MessageChannel;
    import org.springframework.messaging.SubscribableChannel;
    
    public interface StreamClient {
    
        String INPUT = "messageInput";
        String OUTPUT = "messageOut";
    
        @Input(INPUT)
        SubscribableChannel input();
    
        @Output(OUTPUT)
        MessageChannel output();
    
    }
    
  4. Создайте получателя сообщения, где получена первая строка

    @Component
    @EnableBinding(StreamClient.class)
    @Slf4j
    public class StreamReceiver {
    
        @StreamListener(StreamClient.OUTPUT)
        public void process(String obj){
            log.info("StreamReceiver: " + obj);
        }
    }
    
  5. Создать отправителя сообщения

    import com.solo.order.message.StreamClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.messaging.support.MessageBuilder;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.Date;
    
    @RestController
    public class SendMessageController {
    
        @Autowired
        private StreamClient streamClient;
    
        @GetMapping("/sendMessage")
        public void send() {
            String message = "now: " + new Date();
            streamClient.output().send(MessageBuilder.withPayload(message).build());
        }
    }
    

    Обратите внимание, что MessageBuilder не указывает неправильный пакет

9.2 Группировка сообщений

Если одновременно открыто несколько экземпляров, возможно, что несколько экземпляров получат сообщения.Чтобы избежать этой проблемы, вы можете использовать группировку сообщений.

добавить в конфигурационный файл

spring:
  cloud:
    #消息分组
    stream:
      bindings:
        messageInput:  #自己定义的队列名
          group: order # group 名可以随意起

9.3 Отправка и получение объектов

Дооснащение приемника сообщений

/**
* 接收对象
* @param dto
*/
@StreamListener(StreamClient.OUTPUT)
public void process(OrderDTO dto){
	log.info("StreamReceiver: " + dto);
}

Модифицированный отправитель сообщений

/**
* 发送对象
*/
@GetMapping("/sendMessage")
public void send() {
    OrderDTO dto = new OrderDTO();
    dto.setOrderId("12345678");
    streamClient.output().send(MessageBuilder.withPayload(dto).build());
}

Если вы хотите видеть сериализованную строку json вместо имени объекта в консоли MQ, измените конфигурацию следующим образом.

 spring:
  cloud:
    #消息分组
    stream:
      bindings:
        messageInput:  #自己定义的队列名
          group: order # group 名可以随意起
 		  content-type: application/json  #让mq里显示json字符串而不是对象

Добавить кcontent-type: application/json

9.4 Ответ на сообщение

Добавьте два интерфейса в StreamClient

public interface StreamClient {

    String INPUT = "messageInput";
    String OUTPUT = "messageOut";
    String INPUT2 = "messageInput2";
    String OUTPUT2 = "messageOut2";

    @Input(INPUT)
    SubscribableChannel input();

    @Output(OUTPUT)
    MessageChannel output();

    @Input(INPUT2)
    SubscribableChannel input2();

    @Output(OUTPUT2)
    MessageChannel output2();

}

Получатель сообщения вносит следующие изменения

@StreamListener(StreamClient.OUTPUT)
@SendTo(StreamClient.OUTPUT2)
public String process(OrderDTO dto){
    log.info("StreamReceiver: " + dto);
    return "Received...";
}

@StreamListener(StreamClient.OUTPUT2)
public void process2(String msg){
	log.info("StreamReceiver2: " + msg);
}

Главное — добавить@SendTo(StreamClient.OUTPUT2)Аннотируйте, а затем верните желаемое значение. определить другой приемStreamClient.OUTPUT2получатель .

10. Установка Redis и простое использование

10.1 Установка

Установить и запустить через Docker

docker run -d -p 6379:6379 redis:4.0.8

Инструмент визуализации Redis под Mac:Redis Desktop Manager, Относится к РДМ

10.2 Использование

Сначала добавьте зависимости

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

Затем настройте адрес и номер порта redis

  spring:
    redis:
      host: localhost
      port: 6379

11. Сервисный шлюз Zuul

11.1 Введение

Элементы сервисного шлюза

  • Стабильность и высокая доступность
  • производительность, параллелизм
  • безопасность
  • Расширяемость

Общие шлюзовые решения

  • Nginx + Lua
  • Kong (на основе Nginx + Lua)
  • Tyk
  • Spring Cloud Zuul

Особенности Зуула

  • маршрут + фильтр
  • Ядро представляет собой серию фильтров

Четыре API фильтров Zuul

  • Фронт (предварительно)
  • Маршрут
  • Пост (Пост)
  • Ошибка

11.2 Реализация простой маршрутизации и переадресации с помощью Zuul

Создайте новый API-шлюз проекта, отметьте три параметра Cloud Config -> Config Client, CloudDiscovery -> Eureka Discovery, Cloud Routing -> Zuul, нажмите «Далее», чтобы завершить создание.

Исправлятьapplication.propertiesфайлbootstrap.ymlИ выполните следующую настройку

spring:
  application:
    name: api-gateway

  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: dev

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Добавить начальный класс@EnableZuulProxyаннотация

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

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

Запустите проект на порту 9000, вы можете получить доступ к API других проектов через шлюз

Чтобы получить доступ к проекту продуктаproduct/listинтерфейс, ввод прямо в браузереhttp://localhost:9000/product/product/listВот и все.

Формат доступаhttp://localhost:9000/应用id/api地址

11.3 Пользовательская маршрутизация

bootstrap.ymlДобавить к

zuul:
  routes:
    myProduct:  #自己定义的名字
      path: /myProduct/**
      serviceId: product

может пройтиhttp://localhost:9000/myProduct/product/listполучить доступ к вышеуказанному интерфейсу

Лаконичное письмо

zuul:
  routes:
    product: /myProduct/**

11.4 Исключение некоторых маршрутов

исключать/product/list, делая его недоступным

zuul:
  routes:
  # 简介写法
    product: /myProduct/**
  # 排除某些路由
  ignored-patterns:
    - /**/product/list

11.5 Файлы cookie и динамическая маршрутизация

читать куки

По умолчанию файлы cookie будут отфильтрованы. Если вы хотите получить файлы cookie, установитьsensitiveHeaders:может быть пустым

zuul:
  routes:
    myProduct:
      path: /myProduct/**
      serviceId: product
      sensitiveHeaders: 

Установить конфиденциальные заголовки глобально

zuul:
  # 全局设置敏感头
  sensitive-headers:

Динамическая настройка маршрутизации

Новое в Gitapi-gateway-dev.ymlПереместите конфигурацию zuul в git

Создайте новый класс конфигурации или напрямую напишите префикс в классе входа, чтобы получить конфигурацию.

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

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

    @ConfigurationProperties("zuul")
    @RefreshScope
    public ZuulProperties ZuulProperties(){
        return new ZuulProperties();
    }
}

11.6 Предварительные и постфильтры

Проверка токена с предварительным фильтром

Далее используется предварительный фильтр Zuul для реализации запрошенной проверки токена.

новыйTokenFilter

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

@Component
public class TokenFilter extends ZuulFilter {

    @Override
    public String filterType() {

        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        //这里从url里获取,也可以从
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

Запросы без токена сообщат об ошибке 401.

Используйте фильтр сообщений, чтобы добавить содержимое в заголовок возврата.

новыйAddResponseFilter

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;

import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@Component
public class AddResponseFilter 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 requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.addHeader("X-Foo", UUID.randomUUID().toString());
        return null;
    }
}

добавлено в заголовок возвратаX-Foo, интерфейс запроса перезапуска проекта обнаружил, что значение было успешно добавлено

11.7 Ограничение тока Зуула

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import com.solo.apigateway.exception.RateLimitException;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_DETECTION_FILTER_ORDER;

/**
 * 限流拦截器. 令牌桶, 用 google 的 guava 实现
 */
public class RateLimitFilter extends ZuulFilter {

    public static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return SERVLET_DETECTION_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {
        if (RATE_LIMITER.tryAcquire()){
            throw new RateLimitException();
        }
        return null;
    }
}

12. Аутентификация Zuul и добавление пользовательских сервисов

быть улучшенным

Тринадцать, междоменный Зуул

Существует множество решений междоменных проблем, которые можно аннотировать на одном интерфейсе или единообразно обрабатывать на шлюзе Zuul.

13.1 Добавьте аннотации к интерфейсам для достижения междоменного взаимодействия

добавить в интерфейс@CrossOriginАннотация может сделать этот интерфейс междоменным

13.2 Zuul решает междоменную проблему

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

/**
 * 跨域配置
 */
@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); //是否支持 cookie 跨域
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedMethods(Arrays.asList("*"));
        config.setMaxAge(300l); //缓存时间。在这个时间段内,相同的跨域请求将不再检查

        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

По мере развития проекта с открытым исходным кодом на более позднем этапе будет написан ряд статей, чтобы подробно представить эти технологии в сочетании с реальным боем проекта.Добро пожаловать, чтобы обратить внимание~

адрес проекта:GitHub.com/cache Cats/ из…