详解spring集成mina实现服务端主动推送(包含心跳检测)

本文介绍了spring集成mina实现服务端主动推送(包含心跳检测),分享给大家,具体如下:

服务端

1.常规的spring工程集成mina时,pom.xml中需要加入如下配置:

  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.7</version>
  </dependency>
  <dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-integration-beans</artifactId>
    <version>2.0.13</version>
  </dependency>
  <dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-core</artifactId>
    <version>2.0.13</version>
    <type>bundle</type>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-integration-spring</artifactId>
    <version>1.1.7</version>
  </dependency>

注意此处mina-core的配置写法。如果工程中引入上述依赖之后报错:Missing artifact xxx bundle,则需要在pom.xml的plugins之间加入如下插件配置:

  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
  </plugin>

2.Filter1:编解码器,实现ProtocolCodecFactory解码工厂

package com.he.server;
import java.nio.charset.Charset;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineDecoder;
import org.apache.mina.filter.codec.textline.TextLineEncoder;
public class MyCodeFactory implements ProtocolCodecFactory {
  private final TextLineEncoder encoder;
  private final TextLineDecoder decoder;
  public MyCodeFactory() {
    this(Charset.forName("utf-8"));
  }
  public MyCodeFactory(Charset charset) {
    encoder = new TextLineEncoder(charset, LineDelimiter.UNIX);
    decoder = new TextLineDecoder(charset, LineDelimiter.AUTO);
  }
  public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
    // TODO Auto-generated method stub
    return decoder;
  }
  public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
    // TODO Auto-generated method stub
    return encoder;
  }
  public int getEncoderMaxLineLength() {
    return encoder.getMaxLineLength();
  }
  public void setEncoderMaxLineLength(int maxLineLength) {
    encoder.setMaxLineLength(maxLineLength);
  }
  public int getDecoderMaxLineLength() {
    return decoder.getMaxLineLength();
  }
  public void setDecoderMaxLineLength(int maxLineLength) {
    decoder.setMaxLineLength(maxLineLength);
  }
}

此处使用了mina自带的TextLineEncoder编解码器,此解码器支持使用固定长度或者固定分隔符来区分上下两条消息。如果要使用自定义协议,则需要自己编写解码器。要使用websocket,也需要重新编写解码器,关于mina结合websocket,jira上有一个开源项目https://issues.apache.org/jira/browse/DIRMINA-907,专门为mina编写了支持websocket的编解码器,亲测可用。。。此部分不是本文重点,略。

3.Filter2:心跳工厂,加入心跳检测功能需要实现KeepAliveMessageFactory:

package com.he.server;
import org.apache.log4j.Logger;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
public class MyKeepAliveMessageFactory implements KeepAliveMessageFactory{

  private final Logger LOG = Logger.getLogger(MyKeepAliveMessageFactory.class);

  /** 心跳包内容 */
  private static final String HEARTBEATREQUEST = "1111";
  private static final String HEARTBEATRESPONSE = "1112";
  public Object getRequest(IoSession session) {
    LOG.warn("请求预设信息: " + HEARTBEATREQUEST);
     return HEARTBEATREQUEST;
  }
  public Object getResponse(IoSession session, Object request) {
    LOG.warn("响应预设信息: " + HEARTBEATRESPONSE);
    /** 返回预设语句 */
    return HEARTBEATRESPONSE;
  }
  public boolean isRequest(IoSession session, Object message) {
     LOG.warn("请求心跳包信息: " + message);
     if (message.equals(HEARTBEATREQUEST))
       return true;
     return false;
  }
  public boolean isResponse(IoSession session, Object message) {
   LOG.warn("响应心跳包信息: " + message);
   if(message.equals(HEARTBEATRESPONSE))
     return true;
    return false;
  }
}

此处我设置服务端发送的心跳包是1111,客户端应该返回1112.

4.实现必不可少的IoHandlerAdapter,得到监听事件处理权:

package com.he.server;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
public class MyHandler extends IoHandlerAdapter {
  //private final int IDLE = 3000;//(单位s)
  private final Logger LOG = Logger.getLogger(MyHandler.class);
  // public static Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>());
  public static ConcurrentHashMap<Long, IoSession> sessionsConcurrentHashMap = new ConcurrentHashMap<Long, IoSession>();
  @Override
  public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
    session.closeOnFlush();
    LOG.warn("session occured exception, so close it." + cause.getMessage());
  }
  @Override
  public void messageReceived(IoSession session, Object message) throws Exception {
    String str = message.toString();
    LOG.warn("客户端" + ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress() + "连接成功!");
    session.setAttribute("type", message);
    String remoteAddress = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
    session.setAttribute("ip", remoteAddress);
    LOG.warn("服务器收到的消息是:" + str);
    session.write("welcome by he");
  }
  @Override
  public void messageSent(IoSession session, Object message) throws Exception {
    LOG.warn("messageSent:" + message);
  }
  @Override
  public void sessionCreated(IoSession session) throws Exception {
    LOG.warn("remote client [" + session.getRemoteAddress().toString() + "] connected.");
    // my
    Long time = System.currentTimeMillis();
    session.setAttribute("id", time);
    sessionsConcurrentHashMap.put(time, session);
  }
  @Override
  public void sessionClosed(IoSession session) throws Exception {
    LOG.warn("sessionClosed.");
    session.closeOnFlush();
    // my
    sessionsConcurrentHashMap.remove(session.getAttribute("id"));
  }
  @Override
  public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
    LOG.warn("session idle, so disconnecting......");
    session.closeOnFlush();
    LOG.warn("disconnected.");
  }
  @Override
  public void sessionOpened(IoSession session) throws Exception {
    LOG.warn("sessionOpened.");
    //
    //session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, IDLE);
  }
}

此处有几点说明:

第一点:网上教程会在此处(sessionOpened()方法中)设置IDLE,IDLE表示session经过多久判定为空闲的时间,单位s,上述代码中已经注释掉了,因为后面在spring配置中加入心跳检测部分时会进行IDLE的配置,已经不需要在此处进行配置了,而且如果在心跳配置部分和此处都对BOTH_IDLE模式设置了空闲时间,亲测发现此处配置不生效。

第二点:关于存放session的容器,建议使用

代码如下:

public static ConcurrentHashMap<Long, IoSession> sessionsConcurrentHashMap = new ConcurrentHashMap<Long, IoSession>();

而不是用已经注释掉的Collections.synchronizedSet类型的set或者map,至于原因,java5中新增了ConcurrentMap接口和它的一个实现类ConcurrentHashMap,可以保证线程的足够安全。详细的知识你应该搜索SynchronizedMap和ConcurrentHashMap的区别,学习更加多的并发安全知识。

上述代码中,每次在收到客户端的消息时,我会返回一段文本:welcome by he。

有了map,主动推送就不是问题了,想推给谁,在map中找到谁就可以了。

5.完成spring的配置工作

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
      <map>
        <entry key="java.net.SocketAddress"
          value="org.apache.mina.integration.beans.InetSocketAddressEditor">
        </entry>
      </map>
    </property>
  </bean>
  <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
    init-method="bind" destroy-method="unbind">
    <!--端口号-->
    <property name="defaultLocalAddress" value=":8888" />
    <!--绑定自己实现的handler-->
    <property name="handler" ref="serverHandler" />
    <!--声明过滤器的集合-->
    <property name="filterChainBuilder" ref="filterChainBuilder" />
    <property name="reuseAddress" value="true" />
  </bean>

  <bean id="filterChainBuilder"
    class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
    <property name="filters">
      <map>
        <!--mina自带的线程池filter-->
        <entry key="executor" value-ref="executorFilter" />
        <entry key="mdcInjectionFilter" value-ref="mdcInjectionFilter" />
        <!--自己实现的编解码器filter-->
        <entry key="codecFilter" value-ref="codecFilter" />
        <!--日志的filter-->
        <entry key="loggingFilter" value-ref="loggingFilter" />
        <!--心跳filter-->
        <entry key="keepAliveFilter" value-ref="keepAliveFilter" />
      </map>
    </property>
  </bean>
 <!-- executorFilter多线程处理 -->
  <bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter" />
  <bean id="mdcInjectionFilter" class="org.apache.mina.filter.logging.MdcInjectionFilter">
    <constructor-arg value="remoteAddress" />
  </bean>

  <!--日志-->
  <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />

  <!--编解码-->
  <bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
    <constructor-arg>
      <!--构造函数的参数传入自己实现的对象-->
      <bean class="com.he.server.MyCodeFactory"></bean>
    </constructor-arg>
  </bean>

  <!--心跳检测filter-->
  <bean id="keepAliveFilter" class="org.apache.mina.filter.keepalive.KeepAliveFilter">
    <!--构造函数的第一个参数传入自己实现的工厂-->
    <constructor-arg>
      <bean class="com.he.server.MyKeepAliveMessageFactory"></bean>
    </constructor-arg>
    <!--第二个参数需要的是IdleStatus对象,value值设置为读写空闲-->
    <constructor-arg type = "org.apache.mina.core.session.IdleStatus" value="BOTH_IDLE" >
    </constructor-arg>
    <!--心跳频率,不设置则默认60s -->
    <property name="requestInterval" value="5" />
    <!--心跳超时时间,不设置则默认30s  -->
    <property name="requestTimeout" value="10" />
    <!--不设置默认false-->
    <property name="forwardEvent" value="true" />
  </bean>

  <!--自己实现的handler-->
  <bean id="serverHandler" class="com.he.server.MyHandler" />
</beans>

好了,xml中已经写了足够多的注释了。说明一下关于心跳检测中的最后一个属性:forwardEvent,默认false,比如在心跳频率为5s时,实际上每5s会触发一次KeepAliveFilter中的session_idle事件,该事件中开始发送心跳包。当此参数设置为false时,对于session_idle事件不再传递给其他filter,如果设置为true,则会传递给其他filter,例如handler中的session_idle事件,此时也会被触发。另外IdleStatus一共有三个值,点击进源码就能看到。

6.写main方法启动服务端

package com.he.server;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext ct = new ClassPathXmlApplicationContext("applicationContext.xml");
  }
}

run之后,端口就已经开始监听了。此处,如果是web工程,使用tomcat之类的容器,只要在web.xml中配置了

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

则容器在启动时就会加载spring的配置文件,端口的监听就开始了,这样就不需要main方法来启动。

客户端,本文采用两种方式来实现客户端

方式一:用mina结构来实现客户端,引入mina相关jar包即可,Android也可以使用

1.先实现IoHandlerAdater得到监听事件,类似于服务端:

package com.he.client.minaclient;
import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
public class ClientHandler extends IoHandlerAdapter{
  private final Logger LOG = Logger.getLogger(ClientHandler.class); 

  @Override
  public void messageReceived(IoSession session, Object message) throws Exception {
    // TODO Auto-generated method stub
    LOG.warn("客户端收到消息:" + message);
    if (message.toString().equals("1111")) {
      //收到心跳包
      LOG.warn("收到心跳包");
      session.write("1112");
    }
  }

  @Override
  public void messageSent(IoSession session, Object message) throws Exception {
    // TODO Auto-generated method stub
    super.messageSent(session, message);
  }

  @Override
  public void sessionClosed(IoSession session) throws Exception {
    // TODO Auto-generated method stub
    super.sessionClosed(session);
  }

  @Override
  public void sessionCreated(IoSession session) throws Exception {
    // TODO Auto-generated method stub
    super.sessionCreated(session);
  }

  @Override
  public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
    // TODO Auto-generated method stub
    super.sessionIdle(session, status);
  }

  @Override
  public void sessionOpened(IoSession session) throws Exception {
    // TODO Auto-generated method stub
    super.sessionOpened(session);
  }
}

2.写main方法启动客户端,连接服务端:

package com.he.client.minaclient;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
public class ClientTest {
  public static void main(String[] args) throws InterruptedException {
    //创建客户端连接器.
    NioSocketConnector connector = new NioSocketConnector();
    connector.getFilterChain().addLast("logger", new LoggingFilter());
    connector.getFilterChain().addLast("codec",
        new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("utf-8")))); //设置编码过滤器
    connector.setHandler(new ClientHandler());//设置事件处理器
    ConnectFuture cf = connector.connect(new InetSocketAddress("127.0.0.1", 8888));//建立连接
    cf.awaitUninterruptibly();//等待连接创建完成
    cf.getSession().write("hello,测试!");//发送消息,中英文都有
    //cf.getSession().closeOnFlush();
    //cf.getSession().getCloseFuture().awaitUninterruptibly();//等待连接断开
    //connector.dispose();
  }
}

过程也是一样的,加各种filter,绑定handler。上述代码运行之后向服务器发送了:“hello,测试”,并且收到返回值:welcome by he。然后每隔5s,就会收到服务端的心跳包:1111。在handler的messageReceived中,确认收到心跳包之后返回1112,实现心跳应答。以上过程,每5s重复一次。

main方法中最后三行注释掉的代码如果打开,客户端在发送完消息之后会主动断开。

方式二:客户端不借助于mina,换用java的普通socket来实现,这样就可以换成其他任何语言:

package com.he.client;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
/**
 *@function:java的简单socket连接,长连接,尝试连续从服务器获取消息
 *@parameter:
 *@return:
 *@date:2016-6-22 下午03:43:18
 *@author:he
 *@notice:
 */
public class SocketTestTwo {
  public static final String IP_ADDR = "127.0.0.1";// 服务器地址
  public static final int PORT = 8888;// 服务器端口号
  static String text = null;
  public static void main(String[] args) throws IOException {
    System.out.println("客户端启动...");
    Socket socket = null;
    socket = new Socket(IP_ADDR, PORT);
    PrintWriter os = new PrintWriter(socket.getOutputStream());
    os.println("al");
    os.println("two");
    os.flush();
    while (true) {
      try {
        // 创建一个流套接字并将其连接到指定主机上的指定端口号
        DataInputStream input = new DataInputStream(socket.getInputStream());
        // 读取服务器端数据
        byte[] buffer;
        buffer = new byte[input.available()];
        if (buffer.length != 0) {
          System.out.println("length=" + buffer.length);
          // 读取缓冲区
          input.read(buffer);
          // 转换字符串
          String three = new String(buffer);
          System.out.println("内容=" + three);
          if (three.equals("1111\n")) {
            System.out.println("发送返回心跳包");
            os = new PrintWriter(socket.getOutputStream());
            os.println("1112");
            os.flush();
          }
        }
      } catch (Exception e) {
        System.out.println("客户端异常:" + e.getMessage());
        os.close();
      }
    }
  }
}

以上代码运行效果和前一种方式完全一样。

但是注意此种方法和使用mina结构的客户端中有一处不同:对于心跳包的判断。本教程中服务端选用了mina自带的编解码器,通过换行符来区分上下两条消息,也就是每一条消息后面会带上一个换行符,所以在使用java普通的socket来连接时,判断心跳包不再是判断是否为“1111”,而是“1111\n”。对比mina结构的客户端中并不需要加上换行符是因为客户端中绑定了相同的编解码器。

程序运行结果截图:

服务端:

客户端:

红色的打印是mina自带的打印信息,黑色的是本工程中使用的log4j打印,所以你们的工程应该配置有如下log4j的配置文件才能看到一样的打印结果:

log4j.rootLogger=WARN,stdout

log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.Threshold=WARN
log4j.appender.stdout.layout.ConversionPattern = [%-5p] [%d{yyyy-MM-dd HH\:mm\:ss,SSS}] [%x] %c %l - %m%n

应大家需求,工程代码终于抽空放到github了! https://github.com/smile326/minaSpring

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解spring集成mina实现服务端主动推送(包含心跳检测)

    本文介绍了spring集成mina实现服务端主动推送(包含心跳检测),分享给大家,具体如下: 服务端 1.常规的spring工程集成mina时,pom.xml中需要加入如下配置: <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.7</version> </dependency>

  • 详解Spring集成Redis的两种方式

    目录 一.使用Jedis方式集成 1.增加依赖 2.配置项 3.配置连接池 4.测试 使用spring-data-redis 1.引入依赖 2.配置项 3.使用 4.可能会遇到的坑 哨兵和集群 总结: 在工作中,我们用到分布式缓存的时候,第一选择就是Redis,今天介绍一下SpringBoot如何集成Redis的,分别使用Jedis和Spring-data-redis两种方式. 一.使用Jedis方式集成 1.增加依赖 <!-- spring-boot-starter-web不是必须的,这里是为

  • 详解spring cloud构建微服务架构的网关(API GateWay)

    前言 在我们前面的博客中讲到,当服务A需要调用服务B的时候,只需要从Eureka中获取B服务的注册实例,然后使用Feign来调用B的服务,使用Ribbon来实现负载均衡,但是,当我们同时向客户端暴漏多个服务的时候,客户端怎么调用我们暴漏的服务了,如果我们还想加入安全认证,权限控制,过滤器以及动态路由等特性了,那么就需要使用Zuul来实现API GateWay了,下面,我们先来看下Zuul怎么使用. 一.加入Zuul的依赖 <dependency> <groupId>org.spri

  • 详解基于Angular4+ server render(服务端渲染)开发教程

    目标: 1.更好的 SEO,方便搜索爬虫抓取页面内容 2.更快的内容到达时间(time-to-content) 影响: 1.用户:比原来更快的看到渲染的页面,提升用户体验 2.开发人员:某些代码可能需要特殊处理,才能在服务器渲染应用程序中运行(window,document, navigator等) 安装: 1.nodejs 建议6+ 2.angular建议4.1+ 理论实现: 尽管这是一张来自vue官网服务器渲染的一张示意图,但是原理上和angular都是一样的,只是实现的代码不一致. SSR

  • 详解如何使用Vue2做服务端渲染

    花费了一个月时间,终于在新养车之家项目中成功部署了vue2服务端渲染(SSR),并且使用上了Vuex 负责状态管理,首屏加载时间从之前4G网络下的1000ms,提升到了现在500-700ms之间,SSR的优势有很多,现在让我来跟你细细道来. 技术栈 服务端:Nodejs(v6.3) 前端框架 Vue2.1.10 前端构建工具:webpack2.2 && gulp 代码检查:eslint 源码:es6 前端路由:vue-router2.1.0 状态管理:vuex2.1.0 服务端通信:axi

  • 详解使用Next.js构建服务端渲染应用

    next.js简介 最近在学React.js,React官方推荐使用next.js框架作为构建服务端渲染的网站,所以今天来研究一下next.js的使用. next.js作为一款轻量级的应用框架,主要用于构建静态网站和后端渲染网站. 框架特点 使用后端渲染 自动进行代码分割(code splitting),以获得更快的网页加载速度 简洁的前端路由实现 使用webpack进行构建,支持模块热更新(Hot Module Replacement) 可与主流Node服务器进行对接(如express) 可自

  • 详解Spring Boot Admin监控服务上下线邮件通知

    本文介绍了Spring Boot Admin监控服务上下线邮件通知,分享给大家,具体如下: 微服务架构下,服务的数量少则几十,多则上百,对服务的监控必不可少. 如果是以前的单体项目,启动了几个项目是固定的,可以通过第三方的监控工具对其进行监控,然后实时告警. 在微服务下,服务数量太多,并且可以随时扩展,这个时候第三方的监控功能就不适用了,我们可以通过Spring Boot Admin连接注册中心来查看服务状态,这个只能在页面查看. 很多时候更希望能够自动监控,通过邮件告警,某某服务下线了这样的功

  • 详解Spring Cloud Consul 实现服务注册和发现

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式.通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂.易部署和易维护的分布式系统开发工具包. Spring Cloud 包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Sprin

  • 详解Spring Boot 部署与服务配置

    spring Boot 其默认是集成web容器的,启动方式由像普通Java程序一样,main函数入口启动.其内置Tomcat容器或Jetty容器,具体由配置来决定(默认Tomcat).当然你也可以将项目打包成war包,放到独立的web容器中(Tomcat.weblogic等等),当然在此之前你要对程序入口做简单调整. 项目构建我们使用Maven或Gradle,这将使项目依赖.jar包管理.以及打包部署变的非常方便. 一.内嵌 Server 配置 Spring Boot将容器内置后,它通过配置文件

  • 详解Spring Cloud Gateway基于服务发现的默认路由规则

    1.Spring Gateway概述 1.1 什么是Spring Cloud Gateway Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式.Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由

随机推荐