Zuul implements Groovy loading dynamic Filter

One, what is a dynamic filter

Zuul provides a framework that can dynamically load, compile, and run filters. These filters are written by Groovy and placed in a specific directory on Zuul Server. Zuul will poll these directories on a regular basis, and the modified filters will be dynamically loaded into Zuul Server. In this way, if you want to change the filter, you don’t need to republish the gateway, just upload the filter to the specified directory.

Below we will expand based on spring-cloud-starter-zuul (SpringCloud version is Edgware.SR3) to realize the function of dynamically loading Filter

Second, Zuul dynamic Filter implementation

1), add groovy dependency

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

2), load the Groovy script

In normal development, it is sometimes necessary to implement functions that are executed after the project is started. A simple implementation solution provided by SpringBoot is to add a Bean and implement the CommandLineRunner interface. The code to implement the function is placed in the implemented run method.

For multiple implementation classes of the CommandLineRunner interface, specify the execution order through the @Order annotation

@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), write Groovy script

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
    }

}

Now create a folder to store the filter in the idea directory

The directory where the gateway is loaded is specified in the startup parameters

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

Do not put the Groovy script in the directory first, request the gateway, and there is no log printed in GroovyFilter

Then put the Groovy script in the directory, request the gateway, and print the log as follows:

Insert picture description here

Three, Zuul dynamically loads Filter source code analysis

Let’s take a look at how Zuul implements dynamic loading of Filter. In GroovyLoadLineRunner, we finally call the FilterFileManager init()method.

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()The method is finally called startPoller(), and a daemon thread is opened here, which will always read files from the directory we specified in a loop, and then put them in the FilterLoader, thus realizing the function of dynamically loading the 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);
        }
    }  

Guess you like

Origin blog.csdn.net/qq_40378034/article/details/109558790