FilterRegistrationBean的原理

目录
一、注册
二、流程分析
1.加载ServletContextInitializer
2.注册ServletContextInitializer
总结
一、注册

@Bean
    public FilterRegistrationBean filterTestRegistrationBean(){
        FilterRegistrationBean filterRegistry = new FilterRegistrationBean();
        filterRegistry.setOrder(Ordered.HIGHEST_PRECEDENCE + 3);
        //注册过滤器
        filterRegistry.setFilter(new ShallowEtagHeaderFilter());
        filterRegistry.addUrlPatterns("/*");
        filterRegistry.setName("eTagFilter");
        return filterRegistry;
    }

二、流程分析
1.加载ServletContextInitializer
(1)项目中使用的服务是undertow,所以就以服务undertow为例,

服务创建工厂UndertowServletWebServerFactory中的内部类Initializer,实现了ServletContainerInitializer接口,接口中就一个onStartup( )方法,会在服务创建过程中调用

public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
            for (ServletContextInitializer initializer : this.initializers) {
                initializer.onStartup(servletContext);
            }
        }

(2)这里的initializers列表,其中之一是ServletWebServerApplicationContext中的lambda表达式,如下

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
        //lambda表达式
        return this::selfInitialize;
    }
    //具体实现
    private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareWebApplicationContext(servletContext);
        registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            //调用ServletContextInitializer 的onStartup()
            beans.onStartup(servletContext);
        }
    }

(3)ServletContextInitializer 的获取

protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }

(4)ServletContextInitializerBeans的构造方法

public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
            Class<? extends ServletContextInitializer>... initializerTypes) {
        this.initializers = new LinkedMultiValueMap<>();
        this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
                : Collections.singletonList(ServletContextInitializer.class);
        //从beanFactory获取ServletContextInitializerBeans
        addServletContextInitializerBeans(beanFactory);
        //从beanFactory获取Servlet、Filter、EventListener,注册为RegistrationBean
        addAdaptableBeans(beanFactory);
        //根据@Order排序
        List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
                .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
                .collect(Collectors.toList());
        this.sortedList = Collections.unmodifiableList(sortedInitializers);
        logMappings(this.initializers);
    }

(5)addServletContextInitializerBeans(beanFactory),通过ServletContextInitializer类型从beanFactory中获取bean,实现接口ServletContextInitializer的bean如FilterRegistrationBean、ServletListenerRegistrationBean等bean会被获取到,然后调用addServletContextInitializerBean( )方法注册bean

private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
            for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
                    initializerType)) {
                addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
            }
        }
    }

(6)addServletContextInitializerBean( )

private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
            ListableBeanFactory beanFactory) {
        if (initializer instanceof ServletRegistrationBean) {
            Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
            //ServletRegistrationBean  Servlet.class
            addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof FilterRegistrationBean) {
            Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
            //过滤器 FilterRegistrationBean Filter.class
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
            String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
            //过滤器 DelegatingFilterProxyRegistrationBean  Filter.class
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof ServletListenerRegistrationBean) {
            EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
            //监听器 ServletListenerRegistrationBean EventListener.class
            addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
        }
        else {
            //ServletContextInitializer.class
            addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
                    initializer);
        }
    }
private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,
            ListableBeanFactory beanFactory, Object source) {
        //保存到多值的map中 MultiValueMap
        this.initializers.add(type, initializer);
        if (source != null) {
            // Mark the underlying source as seen in case it wraps an existing bean
            this.seen.add(source);
        }
        if (logger.isTraceEnabled()) {
            String resourceDescription = getResourceDescription(beanName, beanFactory);
            int order = getOrder(initializer);
            logger.trace("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order="
                    + order + ", resource=" + resourceDescription);
        }
    }

2.注册ServletContextInitializer
(7)获取ServletContextInitializer后,回到第(2)步中,调用onStartup( ),将Servlet、Filter、EventListener注册到servletContext中,源码不展开分析了

for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            //调用ServletContextInitializer 的onStartup()
            beans.onStartup(servletContext);
        }

(8)RegistrationBean.onStartup( )

@Override
    public final void onStartup(ServletContext servletContext) throws ServletException {
        //获取描述信息
        String description = getDescription();
        if (!isEnabled()) {
            logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
            return;
        }
        //注册,以Filter为例
        register(description, servletContext);
    }

(9)register( )

DynamicRegistrationBean.javaprotected final void register(String description, ServletContext servletContext) {
        //注册
        D registration = addRegistration(description, servletContext);
        if (registration == null) {
            logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
            return;
        }
        //配置
        configure(registration);
    }
protected Dynamic addRegistration(String description, ServletContext servletContext) {
        //获取到Filter
        Filter filter = getFilter();
        //注册Filter
        return servletContext.addFilter(getOrDeduceName(filter), filter);
    }
public FilterRegistration.Dynamic addFilter(final String filterName, final Filter filter) {
        ensureNotProgramaticListener();
        ensureNotInitialized();
        final DeploymentInfo deploymentInfo = getDeploymentInfo();
        if (deploymentInfo.getFilters().containsKey(filterName)) {
            return null;
        }
        //创建FilterInfo
        FilterInfo f = new FilterInfo(filterName, filter.getClass(), new ImmediateInstanceFactory<>(filter));
        //添加到DeploymentInfo中filters
        deploymentInfo.addFilter(f);
        //添加到DeploymentImpl的filters中
        deployment.getFilters().addFilter(f);
        return new FilterRegistrationImpl(f, deployment, this);

    }

总结
ServletContextInitializer onStartup 注册Filter、Servlet、EventListener。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.chinasoft.data.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; import com.chinasoft.data.annoation.ProductE; import com.chinasoft.data.annoation.TestE; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.sql.SQLException; /** * Created by VerRan.Liu on 2017/6/23. */ @Configuration @ProductE @TestE public class DruidDBConfig { private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class); @Value("${spring.datasource.url}") private String dbUrl; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.driverClassName}") private String driverClassName; @Value("${spring.datasource.initialSize}") private int initialSize; @Value("${spring.datasource.minIdle}") private int minIdle; @Value("${spring.datasource.maxActive}") private int maxActive; @Value("${spring.datasource.maxWait}") private int maxWait; @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.minEvictableIdleTimeMillis}") private int minEvictableIdleTimeMillis; @Value("${spring.datasource.validationQuery}") private String validationQuery; @Value("${spring.datasource.testWhileIdle}") private boolean testWhileIdle; @Value("${spring.datasource.testOnBorrow}") private boolean testOnBorrow; @Value("${spring.datasource.testOnReturn}") private boolean testOnReturn; @Value("${spring.datasource.poolPreparedStatements}") private boolean poolPreparedStatements; @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") private int maxPoolPreparedStatementPerConnectionSize; @Value("${spring.datasource.filters}") private String filters; @Value("{spring.datasource.connectionProperties}") private String connectionProperties; @Value("${druid.loginUsername}") private String loginUsername; @Value("${druid.loginPassword}") private String loginPassword; @Bean //声明其为Bean实例 @Primary //在同样的DataSource中,首先使用被标注的DataSource public DataSource dataSource(){ DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); //configuration datasource.setInitialSize(initialSize); datasource.setMinIdle(minIdle); datasource.setMaxActive(maxActive); datasource.setMaxWait(maxWait); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setValidationQuery(validationQuery); datasource.setTestWhileIdle(testWhileIdle); datasource.setTestOnBorrow(testOnBorrow); datasource.setTestOnReturn(testOnReturn); datasource.setPoolPreparedStatements(poolPreparedStatements); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); try { datasource.setFilters(filters); } catch (SQLException e) { logger.error("druid configuration initialization filter", e); } datasource.setConnectionProperties(connectionProperties); return datasource; } /** * 注册一个StatViewServlet * @return ServletRegistrationBean */ @Bean public ServletRegistrationBean DruidStatViewServle2(){ //org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*"); //添加初始化参数:initParams //白名单: servletRegistrationBean.addInitParameter("allow","127.0.0.1"); //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page. servletRegistrationBean.addInitParameter("deny","192.168.1.73"); //登录查看信息的账号密码. servletRegistrationBean.addInitParameter("loginUsername",loginUsername); servletRegistrationBean.addInitParameter("loginPassword",loginPassword); //是否能够重置数据. servletRegistrationBean.addInitParameter("resetEnable","false"); return servletRegistrationBean; } /** * 注册一个:filterRegistrationBean * @return FilterRegistrationBean */ @Bean public FilterRegistrationBean druidStatFilter2(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); //添加过滤规则. filterRegistrationBean.addUrlPatterns("/*"); //添加不需要忽略的格式信息. filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*"); return filterRegistrationBean; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值