欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Zuul实现Groovy加载动态Filter

程序员文章站 2022-03-26 22:25:30
一、什么是动态FilterZuul提供了一个能够对过滤器进行动态的加载、编译、运行的框架。这些过滤器是由Groovy写成,被放在Zuul Server上的特定目录下面。Zuul会按期轮询这些目录,修改过的过滤器会动态的加载到Zuul Server中。这样如果要对过滤器有改动,就不用进行网关的重新发布了,只需要把过滤器上传到指定目录即可下面我们就基于spring-cloud-starter-zuul(SpringCloud版本为Edgware.SR3)进行扩展,实现动态加载Filter的功能二、Zuul...

一、什么是动态Filter

Zuul提供了一个能够对过滤器进行动态的加载、编译、运行的框架。这些过滤器是由Groovy写成,被放在Zuul Server上的特定目录下面。Zuul会按期轮询这些目录,修改过的过滤器会动态的加载到Zuul Server中。这样如果要对过滤器有改动,就不用进行网关的重新发布了,只需要把过滤器上传到指定目录即可

下面我们就基于spring-cloud-starter-zuul(SpringCloud版本为Edgware.SR3)进行扩展,实现动态加载Filter的功能

二、Zuul动态Filter实现

1)、添加groovy依赖

        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.12</version>
        </dependency>

2)、加载Groovy脚本

平常开发中有时需要实现在项目启动后执行的功能,SpringBoot提供的一种简单的实现方案就是添加一个Bean并实现CommandLineRunner接口,实现功能的代码放在实现的run方法中

多个CommandLineRunner接口的实现类时,通过@Order注解指定执行顺序

@Component
@Order(value = 1)
public class GroovyLoadLineRunner implements CommandLineRunner {

    @Override
    public void run(String... strings) throws Exception {
        FilterLoader.getInstance().setCompiler(new GroovyCompiler());
        //读取配置,获取脚本根目录
        String scriptRoot = System.getProperty("zuul.filter.root", "groovy/filters");
        //获取刷新间隔
        String refreshInterval = System.getProperty("zuul.filter.refreshInterval", "5");
        if (scriptRoot.length() > 0) {
            scriptRoot = scriptRoot + File.separator;
        }
        FilterFileManager.setFilenameFilter(new GroovyFileFilter());
        FilterFileManager.init(Integer.parseInt(refreshInterval), scriptRoot + "pre",
                scriptRoot + "route", scriptRoot + "post");
    }
}

3)、编写Groovy脚本

import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.RequestContext
import org.apache.catalina.servlet4preview.http.HttpServletRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants

class GroovyFilter extends ZuulFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(GroovyFilter.class)

    @Override
    String filterType() {
        return FilterConstants.PRE_TYPE
    }

    //过滤器优先级
    @Override
    int filterOrder() {
        return 5
    }

    @Override
    boolean shouldFilter() {
        return true
    }

    @Override
    Object run() {
        HttpServletRequest request = (HttpServletRequest) RequestContext.getCurrentContext().getRequest()
        Enumeration<String> headerNames = request.getHeaderNames()
        while (headerNames.hasMoreElements()) {
            String name = (String) headerNames.nextElement()
            String value = request.getHeader(name)
            LOGGER.info("header: " + name + ":" + value)
        }
        LOGGER.info("This is Groovy Filter")
        return null
    }

}

现在idea目录中创建存放过滤器的文件夹

Zuul实现Groovy加载动态Filter

启动参数中指定加载网关的目录

-Dzuul.filter.root=/Users/hanxiantao/Desktop/学习笔记/Zuul深入学习/zuul_lab/lab05/zuul_gateway/groovy/filters

先不把Groovy脚本放到目录下,请求网关,并没有GroovyFilter中打印的日志

再把Groovy脚本放到目录下,请求网关,打印日志如下:

Zuul实现Groovy加载动态Filter

三、Zuul动态加载Filter源码解析

下面我们来看下Zuul是如何实现动态加载Filter的,GroovyLoadLineRunner中我们最后调用了FilterFileManager的init()方法

public class FilterFileManager {

    /**
     * Initialized the GroovyFileManager.
     *
     * @param pollingIntervalSeconds the polling interval in Seconds
     * @param directories            Any number of paths to directories to be polled may be specified
     * @throws IOException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static void init(int pollingIntervalSeconds, String... directories) throws Exception, IllegalAccessException, InstantiationException {
        if (INSTANCE == null) INSTANCE = new FilterFileManager();

        INSTANCE.aDirectories = directories;
        INSTANCE.pollingIntervalSeconds = pollingIntervalSeconds;
        INSTANCE.manageFiles();
        INSTANCE.startPoller();

    }

init()方法最后调用了startPoller(),这里开启了一个守护线程,会一直循环从我们指定的目录下读取文件,然后放到FilterLoader中,从而实现了动态加载Filter的功能

public class FilterFileManager {

    void startPoller() {
        poller = new Thread("GroovyFilterFileManagerPoller") {
            public void run() {
                while (bRunning) {
                    try {
                        sleep(pollingIntervalSeconds * 1000);
                        manageFiles();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        poller.setDaemon(true);
        poller.start();
    }
  
    void manageFiles() throws Exception, IllegalAccessException, InstantiationException {
        List<File> aFiles = getFiles();
        processGroovyFiles(aFiles);
    }
  
    /**
     * puts files into the FilterLoader. The FilterLoader will only addd new or changed filters
     *
     * @param aFiles a List<File>
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    void processGroovyFiles(List<File> aFiles) throws Exception, InstantiationException, IllegalAccessException {

        for (File file : aFiles) {
            FilterLoader.getInstance().putFilter(file);
        }
    }  

本文地址:https://blog.csdn.net/qq_40378034/article/details/109558790