gateway动态路由
实体类:
@Data public class AppRoute implements Serializable { private Integer id; private String routeId; private Integer exeseq; private String uri; private String predicates; private String filters; private Date createTime; private Date updateTime; private Integer state; }
监听:
@Service public class RouteHandler implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } /** * 刷新路由方法 * RefreshRouteLocator 会监听该事件,在收到 RefreshRoutesEvent 事件后, 会清空缓存信息,待下次请求时重新加载路由信息并缓存 */ public void refreshRoutes() { publisher.publishEvent(new RefreshRoutesEvent(this)); } }
初始化路由
@Component public class RouteStartListener { private static final Logger logger = LoggerFactory.getLogger(RouteStartListener.class); @Autowired RouteDefinitionRepository repository; @Autowired AppRouteService routeService; @Autowired RefreshRouteLocator refreshRouteLocator; /** * 类加载时读取数据到缓存 */ @PostConstruct public void init() { logger.info("..................................初始化路由数据................................................"); List<AppRoute> routeList = routeService.findAll(); if (routeList != null && routeList.size() > 0) { routeList.forEach(e ->{ Mono<RouteDefinition> routeDefinitionMono = Mono.just(new RouteDefinition(e.toString())); logger.info("..................................写路由信息到缓存................................................"); repository.save(routeDefinitionMono); }); } } @Bean public void routes() { refreshRouteLocator.buildRoutes(); } }
刷新路由
/** * 刷新路由服务 */ @Component public class RefreshRouteLocator implements RouteLocator { private static Logger log = LoggerFactory.getLogger(RefreshRouteLocator.class); private Flux<Route> route; private RouteLocatorBuilder builder; private RouteLocatorBuilder.Builder routesBuilder; @Autowired AppRouteServiceImpl appRouteService; @Autowired private RouteHandler routeHandler; @Autowired RouteDefinitionRepository repository; public RefreshRouteLocator(RouteLocatorBuilder builder) { this.builder = builder; clearRoutes(); } public void clearRoutes() { routesBuilder = builder.routes(); } /** * 配置完成后,调用本方法全量构建路由和刷新路由表 */ public void buildRoutes() { log.info("---------清空路由------------"); clearRoutes(); if (routesBuilder != null) { log.info("---------从数据库读取新数据,全量刷新路由------------"); appRouteService.findAll().forEach(serviceDefinition ->{ String serviceId = serviceDefinition.getRouteId(); // 拼成 uri + path 请求路径 String url = serviceDefinition.getUri(); String predicates = serviceDefinition.getPredicates(); String[] filterNames = serviceDefinition.getFilters().split(","); URI uri = UriComponentsBuilder.fromHttpUrl(url + predicates).build().toUri(); List<GatewayFilter> filters = buildFilters(filterNames); routesBuilder.route(serviceId, r -> r.path(predicates).filters(e ->e.filters(filters)).uri(uri)); }); route = routesBuilder.build().getRoutes(); } routeHandler.refreshRoutes(); } /** * 反射生成GatewayFilter * @param filterNames * @return */ private List<GatewayFilter> buildFilters(String[] filterNames) { List<GatewayFilter> filters = new ArrayList<>(); for (String filterName : filterNames){ //反射生成 Class aClass = null; try { aClass = Class.forName(filterName); System.out.println(aClass.getName()); filters.add((GatewayFilter)aClass.newInstance()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } }; return filters; } @Override public Flux<Route> getRoutes() { return route; } }
测试Contro
@RestController @RequestMapping(value = "/app/route") public class AppRouteAction { private AppRouteService appRouteService; @Autowired public void setAppRouteService(AppRouteService appRouteService) { this.appRouteService = appRouteService; } @GetMapping(value = "/list") public JsonResult list() { List<AppRoute> all = appRouteService.findAll(); return new JsonResult(true,all); } @PostMapping(value = "/save") public JsonResult save(@RequestBody AppRoute route) { System.out.println("-------------route----------route----------route-----------"+route); if (route == null || StringUtils.isBlank(route.getRouteId())) { return new JsonResult(false,null, "id不能为空"); } else if (StringUtils.isBlank(route.getUri())) { return new JsonResult(false, null,"uri不能为空"); }else if (StringUtils.isBlank(route.getPredicates())) { return new JsonResult(false, null,"Predicates不能为空"); } AppRoute sameRouteIdObj = appRouteService.findByRouteId(route.getRouteId()); if (sameRouteIdObj != null) { return new JsonResult(false,null, "已存在相同 RouteId 的配置"); } route.setPredicates(route.getPredicates() != null ? route.getPredicates().trim() : null); route.setFilters(route.getFilters() != null ? route.getFilters().trim() : null); boolean res = appRouteService.saveOrUpdate(route); return new JsonResult(res, res ? "操作成功" : "操作失败"); } @DeleteMapping(value = "{routeId}") public JsonResult delete(@PathVariable("routeId") String routeId) { AppRoute route = appRouteService.findByRouteId(routeId); if (route == null || StringUtils.isBlank(route.getRouteId())) { return new JsonResult(false,null, "路由不存在或已删除"); } boolean res = appRouteService.deleteRoute(route); return new JsonResult(res, res ? "操作成功" : "操作失败"); } @GetMapping(value="/clearCache") public void clearCache(){ appRouteService.resetRoute(); } }
访问服务接口
public interface AppRouteService { List<AppRoute> findAll(); boolean saveOrUpdate(AppRoute route); boolean deleteRoute(AppRoute routeId); AppRoute findByRouteId(String routeId); void resetRoute(); }
通过接口访问,对数据进行增删
/** * 刷新路由保存数据库 */ @Service public class AppRouteServiceImpl implements AppRouteService { private static final Logger logger = LoggerFactory.getLogger(AppRouteService.class); @Autowired AppRouteMapper appRouteMapper; @Autowired RouteDefinitionRepository routeDefinitionRepository; @Autowired RouteHandler routeHandler; @Autowired RefreshRouteLocator refreshRouteLocator; /** * 查询所有路由信息 * * @return */ @Override public List<AppRoute> findAll() { return appRouteMapper.findAll(); } /** * 保存、更新 路由 * * @param route * @return */ @Override public boolean saveOrUpdate(AppRoute route) { route.setUpdateTime(new Date()); AppRoute oldRoute = appRouteMapper.findById(route.getId()); boolean res = false; if (oldRoute != null && oldRoute.getId() != null) { res = appRouteMapper.updateRoute(route); } else { res = appRouteMapper.insertRoute(route); } if (res) { logger.info("更新缓存,通知网关重新加载路由信息..."); routeDefinitionRepository.save(Mono.just(new RouteDefinition(route.toString()))); resetRoute(); } return res; } /** * 删除路由 * * @param route * @return */ public boolean deleteRoute(AppRoute route) { route.setUpdateTime(new Date()); boolean res = appRouteMapper.deleteRoute(route); if (res) { logger.info("更新缓存,通知网关重新加载路由信息..."); routeDefinitionRepository.delete(Mono.just(route.getRouteId())); resetRoute(); } return res; } /** * 通过routeId查找路由 * * @param routeId * @return */ @Override public AppRoute findByRouteId(String routeId) { return appRouteMapper.findByRouteId(routeId); } @Override public void resetRoute() { refreshRouteLocator.buildRoutes(); } }
Dao接口
@Repository public interface AppRouteMapper { List<AppRoute> findAll(); AppRoute findByRouteId(String routeId); AppRoute findById(Integer id); boolean updateRoute(AppRoute route); boolean insertRoute(AppRoute route); boolean deleteRoute(@Param("route") AppRoute route); AppRoute findByPath(String path); }
执行sql
<select id="findAll" resultType="com.zqs.domain.dto.route.AppRoute"> select * from tbl_app_route where state = 0 </select> <select id="findByRouteId" parameterType="string" resultType="com.zqs.domain.dto.route.AppRoute"> select * from tbl_app_route where route_Id = #{routeId} and state = 0 LIMIT 1 </select> <select id="findById" parameterType="integer" resultType="com.zqs.domain.dto.route.AppRoute"> select * from tbl_app_route where id = #{id} </select> <select id="findByPath" parameterType="String" resultType="com.zqs.domain.dto.route.AppRoute"> select * from tbl_app_route where predicates = #{path} AND state = 0 </select> <update id="updateRoute"> update tbl_app_route set route_id = #{routeId}, exeseq = #{exeseq}, uri = #{uri}, predicates = #{predicates}, filters = #{filters}, state = 0 where id = #{id} </update> <insert id="insertRoute" parameterType="com.zqs.domain.dto.route.AppRoute"> insert into tbl_app_route( id, route_id, exeseq, uri, predicates, filters) values( #{id}, #{routeId}, #{exeseq}, #{uri}, #{predicates}, #{filters} ); </insert> <update id="deleteRoute" parameterType="com.zqs.domain.dto.route.AppRoute"> update tbl_app_route set state = 1 where id = #{route.id} </update>
主要依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
</exclusions>
</dependency>
浙公网安备 33010602011771号