You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot如何手动注册过滤器并实现有序编排?

解决过滤器生效与有序编排问题

你当前的代码只是把Filter类注册为Spring Bean,但并没有将它们纳入Servlet容器的过滤器链中,所以无法生效。要让过滤器生效并实现内置与自定义过滤器的有序编排,可按以下步骤处理:

一、让已注册Filter生效

Spring中,只有将Filter包装为FilterRegistrationBean注册到容器,Servlet才会将其加入过滤器链。修改你的DefaultFilterRegister,替换原注册逻辑:

@Component
public class DefaultFilterRegister implements BeanDefinitionRegistryPostProcessor {

    private List<Filter> toRegister = FilterUtils.getInitFilters();

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if (CollectionUtils.isEmpty(toRegister)) {
            return;
        }
        for (Filter filter : toRegister) {
            Class<? extends Filter> filterClass = filter.getClass();
            String filterBeanName = filterClass.getName();
            
            // 1. 先注册Filter本身作为Spring Bean(支持依赖注入)
            BeanDefinitionBuilder filterBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(filterClass);
            filterBeanBuilder.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            registry.registerBeanDefinition(filterBeanName, filterBeanBuilder.getRawBeanDefinition());

            // 2. 注册FilterRegistrationBean,将Filter纳入Servlet过滤器链
            BeanDefinitionBuilder registrationBuilder = BeanDefinitionBuilder.genericBeanDefinition(FilterRegistrationBean.class);
            registrationBuilder.addConstructorArgReference(filterBeanName);
            // 设置拦截路径,按需调整,比如/*匹配所有请求
            registrationBuilder.addPropertyValue("urlPatterns", Collections.singletonList("/*"));
            // 给内置过滤器分配默认顺序,值越小越先执行
            registrationBuilder.addPropertyValue("order", getDefaultOrder(filter));

            registry.registerBeanDefinition(filterBeanName + "Registration", registrationBuilder.getRawBeanDefinition());
        }
    }

    // 给内置过滤器分配初始顺序
    private int getDefaultOrder(Filter filter) {
        if (filter instanceof AFilter) return 10;
        if (filter instanceof BFilter) return 20;
        if (filter instanceof CFilter) return 30;
        return 100; // 默认顺序
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

二、实现过滤器有序编排(支持addFilterBefore)

要支持自定义过滤器插入指定位置,需要维护全局的过滤器顺序配置,动态调整所有FilterRegistrationBean的order值。

1. 实现过滤器顺序管理器

@Component
public class FilterOrderManager {
    // 用LinkedHashMap维护有序的过滤器类与顺序映射
    private final LinkedHashMap<Class<? extends Filter>, Integer> filterOrderMap = new LinkedHashMap<>();

    public FilterOrderManager() {
        // 初始化内置过滤器的默认顺序
        filterOrderMap.put(AFilter.class, 10);
        filterOrderMap.put(BFilter.class, 20);
        filterOrderMap.put(CFilter.class, 30);
    }

    // 将自定义过滤器添加到指定过滤器之前
    public void addFilterBefore(Class<? extends Filter> targetFilter, Class<? extends Filter> beforeFilter) {
        Integer beforeOrder = filterOrderMap.get(beforeFilter);
        if (beforeOrder == null) {
            throw new IllegalArgumentException("指定的前置过滤器[" + beforeFilter.getName() + "]不存在");
        }
        // 给后续过滤器的顺序值加10,腾出位置
        filterOrderMap.entrySet().forEach(entry -> {
            if (entry.getValue() >= beforeOrder) {
                entry.setValue(entry.getValue() + 10);
            }
        });
        // 设置自定义过滤器的顺序
        filterOrderMap.put(targetFilter, beforeOrder);
        // 重新排序映射,保证顺序正确
        reorderMap();
    }

    // 将自定义过滤器添加到指定过滤器之后
    public void addFilterAfter(Class<? extends Filter> targetFilter, Class<? extends Filter> afterFilter) {
        Integer afterOrder = filterOrderMap.get(afterFilter);
        if (afterOrder == null) {
            throw new IllegalArgumentException("指定的后置过滤器[" + afterFilter.getName() + "]不存在");
        }
        Integer targetOrder = afterOrder + 10;
        // 调整后续过滤器顺序,避免冲突
        filterOrderMap.entrySet().forEach(entry -> {
            if (entry.getValue() >= targetOrder) {
                entry.setValue(entry.getValue() + 10);
            }
        });
        filterOrderMap.put(targetFilter, targetOrder);
        reorderMap();
    }

    // 重新排序映射,按order值从小到大排列
    private void reorderMap() {
        List<Map.Entry<Class<? extends Filter>, Integer>> sortedList = new ArrayList<>(filterOrderMap.entrySet());
        sortedList.sort(Map.Entry.comparingByValue());
        filterOrderMap.clear();
        sortedList.forEach(entry -> filterOrderMap.put(entry.getKey(), entry.getValue()));
    }

    public LinkedHashMap<Class<? extends Filter>, Integer> getFilterOrderMap() {
        return filterOrderMap;
    }
}

2. 修改注册逻辑,基于顺序管理器动态注册

更新DefaultFilterRegister,结合FilterOrderManager的配置来注册所有过滤器(包括自定义过滤器):

@Component
public class DefaultFilterRegister implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
    private ApplicationContext applicationContext;
    private List<Filter> toRegister = FilterUtils.getInitFilters();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        FilterOrderManager orderManager = applicationContext.getBean(FilterOrderManager.class);
        LinkedHashMap<Class<? extends Filter>, Integer> filterOrderMap = orderManager.getFilterOrderMap();

        // 注册内置过滤器
        registerFilters(registry, toRegister, filterOrderMap);
        // 注册自定义过滤器(比如用户添加的DFilter)
        registerCustomFilters(registry, filterOrderMap);
    }

    private void registerFilters(BeanDefinitionRegistry registry, List<Filter> filters, LinkedHashMap<Class<? extends Filter>, Integer> orderMap) {
        for (Filter filter : filters) {
            registerSingleFilter(registry, filter.getClass(), orderMap);
        }
    }

    private void registerCustomFilters(BeanDefinitionRegistry registry, LinkedHashMap<Class<? extends Filter>, Integer> orderMap) {
        // 遍历所有在顺序管理器中的过滤器,包括自定义的
        for (Class<? extends Filter> filterClass : orderMap.keySet()) {
            if (!registry.containsBeanDefinition(filterClass.getName())) {
                // 如果自定义Filter还没注册为Bean,先注册
                BeanDefinitionBuilder filterBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(filterClass);
                filterBeanBuilder.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
                registry.registerBeanDefinition(filterClass.getName(), filterBeanBuilder.getRawBeanDefinition());
            }
            registerSingleFilter(registry, filterClass, orderMap);
        }
    }

    // 注册单个Filter及其对应的FilterRegistrationBean
    private void registerSingleFilter(BeanDefinitionRegistry registry, Class<? extends Filter> filterClass, LinkedHashMap<Class<? extends Filter>, Integer> orderMap) {
        String filterBeanName = filterClass.getName();
        Integer order = orderMap.getOrDefault(filterClass, 100);

        // 注册FilterRegistrationBean(如果不存在则创建,存在则更新order)
        String registrationBeanName = filterBeanName + "Registration";
        if (registry.containsBeanDefinition(registrationBeanName)) {
            BeanDefinition registrationBean = registry.getBeanDefinition(registrationBeanName);
            registrationBean.getPropertyValues().add("order", order);
        } else {
            BeanDefinitionBuilder registrationBuilder = BeanDefinitionBuilder.genericBeanDefinition(FilterRegistrationBean.class);
            registrationBuilder.addConstructorArgReference(filterBeanName);
            registrationBuilder.addPropertyValue("urlPatterns", Collections.singletonList("/*"));
            registrationBuilder.addPropertyValue("order", order);
            registry.registerBeanDefinition(registrationBeanName, registrationBuilder.getRawBeanDefinition());
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

3. 用户使用示例

当用户需要添加DFilter到BFilter之前时,只需调用顺序管理器的方法:

@Autowired
private FilterOrderManager filterOrderManager;

// 在应用启动时或自定义配置类中调用
public void configureCustomFilters() {
    filterOrderManager.addFilterBefore(DFilter.class, BFilter.class);
}

这样最终过滤器的执行顺序会是:A → D → B → C。


内容的提问来源于stack exchange,提问作者Kusch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 02:10:51