美文网首页
zuul2 FilterFileManager 源码学习

zuul2 FilterFileManager 源码学习

作者: pcgreat | 来源:发表于2020-07-12 11:05 被阅读0次

    感想:
    1 zuul2 没有使用spring 依赖注入 ,bean 管理 ,甚至任何一个spring依赖你都找不到 看来和 spring关系真的很差 ,要不然也不用spring 自己写个网关,不用奈飞天的,而使用google guice 高效简单 ,当然他也不需要spring 全家桶。
    2 此类会起一线程管理groovy filter目录轮询以查找all Groovy过滤器 file,并异步加载他们,加载逻辑在DynamicFilterLoader。轮询间隔和目录是在类的初始化中指定的
    3 这个类在项目其他地方没有看到任何的引用 ,也就是说,生成Singleton instance 它就像一个孤岛一样的存在
    5 还有些小细节 static nest class 的使用 , thread daemon 使用场景 都体现了人家开发功力。

    /*
     * Copyright 2018 Netflix, Inc.
     *
     *      Licensed under the Apache License, Version 2.0 (the "License");
     *      you may not use this file except in compliance with the License.
     *      You may obtain a copy of the License at
     *
     *          http://www.apache.org/licenses/LICENSE-2.0
     *
     *      Unless required by applicable law or agreed to in writing, software
     *      distributed under the License is distributed on an "AS IS" BASIS,
     *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *      See the License for the specific language governing permissions and
     *      limitations under the License.
     */
    package com.netflix.zuul;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import com.netflix.config.DynamicIntProperty;
    import java.io.File;
    import java.io.FilenameFilter;
    import java.io.IOException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.TimeUnit;
    import javax.inject.Inject;
    import javax.inject.Singleton;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * This class manages the directory polling for changes and new Groovy filters.
     * Polling interval and directories are specified in the initialization of the class, and a poller will check
     * for changes and additions.
     *
     * @author Mikey Cohen
     *         Date: 12/7/11
     *         Time: 12:09 PM
     */
    @Singleton
    public class FilterFileManager {
    
        private static final Logger LOG = LoggerFactory.getLogger(FilterFileManager.class);
        // 异步加载 groovy filter 线程数
        private static final DynamicIntProperty FILE_PROCESSOR_THREADS = new DynamicIntProperty("zuul.filterloader.threads", 1);
       // 异步加载 all 变更groovy filter 任务超时时间 ,默认 120s
        private static final DynamicIntProperty FILE_PROCESSOR_TASKS_TIMEOUT_SECS = new DynamicIntProperty("zuul.filterloader.tasks.timeout", 120);
        // 轮询检查groovy filter ,将变更filters 添加异步加载 groovy filter 线程池
        Thread poller;
        boolean bRunning = true;
    
        private final FilterFileManagerConfig config;
        private final FilterLoader filterLoader;
        // 变更filters 添加异步加载 groovy filter 线程池
        private final ExecutorService processFilesService;
    
        @Inject
        public FilterFileManager(FilterFileManagerConfig config, FilterLoader filterLoader) {
            this.config = config;
            this.filterLoader = filterLoader;
            ThreadFactory tf =
                    new ThreadFactoryBuilder().setDaemon(true).setNameFormat("FilterFileManager_ProcessFiles-%d").build();
            this.processFilesService = Executors.newFixedThreadPool(FILE_PROCESSOR_THREADS.get(), tf);
        }
    
        /**
         * Initialized the GroovyFileManager.
         *
         * @throws Exception
         */
        @Inject
        public void init() throws Exception
        {
            long startTime = System.currentTimeMillis();
            filterLoader.putFiltersForClasses(config.getClassNames());
            manageFiles();
            startPoller();
            
            LOG.warn("Finished loading all zuul filters. Duration = " + (System.currentTimeMillis() - startTime) + " ms.");
        }
    
        /**
         * Shuts down the poller
         */
        public void shutdown() {
            stopPoller();
        }
    
        void stopPoller() {
            bRunning = false;
        }
        // 管理groovy filter目录轮询以查找更改和新的Groovy过滤器,并将filters 交给异步加载线程池
        void startPoller() {
            poller = new Thread("GroovyFilterFileManagerPoller") {
                {
                    setDaemon(true);
                }
    
                public void run() {
                    while (bRunning) {
                        try {
                            sleep(config.getPollingIntervalSeconds() * 1000);
                            manageFiles();
                        }
                        catch (Exception e) {
                            LOG.error("Error checking and/or loading filter files from Poller thread.", e);
                        }
                    }
                }
            };
            poller.start();
        }
    
        /**
         * Returns the directory File for a path. A Runtime Exception is thrown if the directory is in valid
         *
         * @param sPath
         * @return a File representing the directory path
         */
        public File getDirectory(String sPath) {
            File  directory = new File(sPath);
            if (!directory.isDirectory()) {
                URL resource = FilterFileManager.class.getClassLoader().getResource(sPath);
                try {
                    directory = new File(resource.toURI());
                } catch (Exception e) {
                    LOG.error("Error accessing directory in classloader. path=" + sPath, e);
                }
                if (!directory.isDirectory()) {
                    throw new RuntimeException(directory.getAbsolutePath() + " is not a valid directory");
                }
            }
            return directory;
        }
    
        /**
         * Returns a List<File> of all Files from all polled directories
         *
         * @return
         */
        List<File> getFiles() {
            List<File> list = new ArrayList<File>();
            for (String sDirectory : config.getDirectories()) {
                if (sDirectory != null) {
                    File directory = getDirectory(sDirectory);
                    File[] aFiles = directory.listFiles(config.getFilenameFilter());
                    if (aFiles != null) {
                        list.addAll(Arrays.asList(aFiles));
                    }
                }
            }
            return list;
        }
    
        /**
         * puts files into the FilterLoader. The FilterLoader will only add new or changed filters
         *
         * @param aFiles a List<File>
         * @throws IOException
         * @throws InstantiationException
         * @throws IllegalAccessException
         */
        void processGroovyFiles(List<File> aFiles) throws Exception {
    
            List<Callable<Boolean>> tasks = new ArrayList<>();
            for (File file : aFiles) {
                tasks.add(() -> {
                    try {
                        return filterLoader.putFilter(file);
                    }
                    catch(Exception e) {
                        LOG.error("Error loading groovy filter from disk! file = " + String.valueOf(file), e);
                        return false;
                    }
                });
            }
            processFilesService.invokeAll(tasks, FILE_PROCESSOR_TASKS_TIMEOUT_SECS.get(), TimeUnit.SECONDS);
        }
    
        void manageFiles()
        {
            try {
                List<File> aFiles = getFiles();
                processGroovyFiles(aFiles);
            }
            catch (Exception e) {
                String msg = "Error updating groovy filters from disk!";
                LOG.error(msg, e);
                throw new RuntimeException(msg, e);
            }
        }
    
        public static class FilterFileManagerConfig
        {
            private String[] directories;
            private String[] classNames;
            private int pollingIntervalSeconds;
            private FilenameFilter filenameFilter;
    
            public FilterFileManagerConfig(String[] directories, String[] classNames, int pollingIntervalSeconds, FilenameFilter filenameFilter) {
                this.directories = directories;
                this.classNames = classNames;
                this.pollingIntervalSeconds = pollingIntervalSeconds;
                this.filenameFilter = filenameFilter;
            }
    
            public String[] getDirectories() {
                return directories;
            }
            public String[] getClassNames()
            {
                return classNames;
            }
            public int getPollingIntervalSeconds() {
                return pollingIntervalSeconds;
            }
            public FilenameFilter getFilenameFilter() {
                return filenameFilter;
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:zuul2 FilterFileManager 源码学习

          本文链接:https://www.haomeiwen.com/subject/ouycuhtx.html