网关集群能够经过Nginx与lvs实现,这里基于Nginx,实现比较简单。为nginx添加以下配置便可java
upstream gateways { server 127.0.0.1:81; server 127.0.0.1:82; } server { listen 80; server_name localhost; logs/host.access.log main; ... location / { proxy_pass http://gateways/; } ... }
任何配置不用重启网关服务器均可以实现及时刷新网关配置。mysql
实现方式:nginx
根据路由的相关配置,咱们设计数据库表结构git
CREATE TABLE `gateway_route` ( `id` int(11) primary key, `route_id` varchar(255) DEFAULT NULL,#路由id `route_name` varchar(255) DEFAULT NULL, `route_pattern` varchar(255) DEFAULT NULL,#路径匹配规则 `route_type` varchar(255) DEFAULT NULL,#跳转类型,0时从注册中心获取地址,1直接跳转网络地址 `route_uri` varchar(255) DEFAULT NULL #与route_type相对应的地址 )
插入以下的路由信息,member-service是注册中心上的服务,可替换成本身的github
根据数据库设计实体类sql
public class GateWayEntity { private Long id; private String routeId; private String routeName; private String routeType; private String routeUri; private String routePattern; ... }
由于要从数据库获取路由信息,这里使用mybatis来访问数据库,接口以下数据库
@Mapper public interface GatewayRouteMapper { //获取所有路由 List<GateWayEntity> getAllRoutes(); }
对应xml以下服务器
<resultMap id="GateWay" type="com.github.zyq.entity.GateWayEntity"> <id column="id" property="id" ></id> <result column="route_id" property="routeId"></result> <result column="route_name" property="routeName"></result> <result column="route_type" property="routeType"></result> <result column="route_uri" property="routeUri"></result> <result column="route_pattern" property="routePattern"></result> </resultMap> <select id="getAllRoutes" resultMap="GateWay"> select id,route_id,route_name,route_type,route_uri,route_pattern from gateway_route </select>
重点即是加载路由信息了,建立一个类实现ApplicationEventPublisherAware接口网络
@Service public class GatewayService implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Autowired private RouteDefinitionWriter routeDefinitionWriter; @Autowired private GatewayRouteMapper gatewayRouteMapper; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } //从数据库获取所有路由,在将每一个路由加载 public void getAllRoutes() { List<GateWayEntity> routes = gatewayRouteMapper.getAllRoutes(); for (GateWayEntity route : routes) { loadRoute(route); } } //根据实体类加载路由 public String loadRoute(GateWayEntity gateWayEntity) { //路由相关的配置 RouteDefinition routeDefinition = new RouteDefinition(); PredicateDefinition predicateDefinition = new PredicateDefinition(); FilterDefinition filterDefinition = new FilterDefinition(); Map<String,String> predicateParams = new HashMap<>(8); URI uri = null; //根据路由类型来决定如何跳转 if ("0".equals(gateWayEntity.getRouteType())) { uri = UriComponentsBuilder.fromUriString("lb://"+gateWayEntity.getRouteUri()+"/").build().toUri(); } else { uri = UriComponentsBuilder.fromHttpUrl(gateWayEntity.getRouteUri()).build().toUri(); } //路由惟一id routeDefinition.setId(gateWayEntity.getRouteId()); predicateDefinition.setName("Path"); //路由转发地址 predicateParams.put("pattern",gateWayEntity.getRoutePattern()); predicateDefinition.setArgs(predicateParams); routeDefinition.setPredicates(Arrays.asList(predicateDefinition)); routeDefinition.setUri(uri); routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe(); this.publisher.publishEvent(new RefreshRoutesEvent(this)); return "seccess"; }
每次路由更改时,只要访问一下数据库,将路由信息加载便可。书写一个controller,调用一下service的getAllRoutes方法加载路由。mybatis
@RestController public class GateWayController { @Autowired private GatewayService gatewayService; @GetMapping("/load") public String loadRoutes() { gatewayService.getAllRoutes(); return "success"; } }
访问一下/load路径加载路由信息,在route_pattern匹配的路径就能访问了,每次修改数据库的路由信息后,只要从新加载,就可以实现动态网关服务。