springboot 创建自定义filter 非常规写法

先来一个很普通的例子, springBoot创建自定义filter

public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("加载进来了");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

然后创建一个bean 将MyFilter注册到FilterRegistrationBean中

	@Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setName("myFilter");
        return filterRegistrationBean;
    }

然后随便访问一个路径,即可看到 “加载进来了” 打印信息
具体的实现过程网上有很多了,这里不再赘述

然后来一个非常规的简化写法,自定义filter保持不变,bean的写法改变如下

	@Bean
    public MyFilter myFilter(){
        return new MyFilter();
    }

再随便访问一个路径, 发现filter依然生效,显然是智能的springboot帮我们做了不少工作
这里简要的贴出相关源码 以做笔记

无论是通过 继承SpringBootServletInitializer 还是通过 SpringApplication.run() 的方式加载springboot, 都会初始化AnnotationConfigServletWebServerApplicationContext
其父类是ServletWebServerApplicationContext

@Override
    //org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
	//最终会执行这段代码
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

   private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
			    //关键是这句,做一些初始化的工作
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context",
						ex);
			}
		}
		initPropertySources();
	}


private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
		return this::selfInitialize;
	}

	private void selfInitialize(ServletContext servletContext) throws ServletException {
		prepareWebApplicationContext(servletContext);
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
				beanFactory);
		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
				getServletContext());
		existingScopes.restore();
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
				getServletContext());
		//关键代码, 获取需要做初始化的bean进行处理
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
			beans.onStartup(servletContext);
		}
	}

//这个获取初始化bean的操作最终交给了ServletContextInitializerBeans处理
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
		return new ServletContextInitializerBeans(getBeanFactory());
}	

接下来看ServletContextInitializerBeans 的重要代码

//可以看出,此类最终要输出 ServletContextInitializer的集合
//也就是说需要将相关的bean 包装成ServletContextInitializer的子类
//而刚好RegistrationBean也实现了ServletContextInitializer接口,似乎快水落石出了
public class ServletContextInitializerBeans
		extends AbstractCollection<ServletContextInitializer> 

//构造方法
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
		this.initializers = new LinkedMultiValueMap<>();
		addServletContextInitializerBeans(beanFactory);
		//重点看这里,使用适配的方式对beanFactory中的bean进行处理
		addAdaptableBeans(beanFactory);
		List<ServletContextInitializer> sortedInitializers = new ArrayList<>();
		this.initializers.values().forEach((contextInitializers) -> {
			AnnotationAwareOrderComparator.sort(contextInitializers);
			sortedInitializers.addAll(contextInitializers);
		});
		this.sortedList = Collections.unmodifiableList(sortedInitializers);
	}

	
	private void addAdaptableBeans(ListableBeanFactory beanFactory) {
		MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
		//获取bean中所有的Servlet类,创建ServletRegistrationBeanAdapter适配器进行处理
		addAsRegistrationBean(beanFactory, Servlet.class,
				new ServletRegistrationBeanAdapter(multipartConfig));
		//同上 处理Filter
		addAsRegistrationBean(beanFactory, Filter.class,
				new FilterRegistrationBeanAdapter());
		//处理相关的EventListener,具体查看ServletListenerRegistrationBean
		for (Class<?> listenerType : ServletListenerRegistrationBean
				.getSupportedTypes()) {
			addAsRegistrationBean(beanFactory, EventListener.class,
					(Class<EventListener>) listenerType,
					new ServletListenerRegistrationBeanAdapter());
		}
	}

到这里基本可以结束了,通过以上源码可以了解
springBoot 会筛选出bean中的 filter、servlet、EventListener 对象,包装成相应的RegistrationBean进行处理
当然了里面的相关属性也是默认的,如果需要自定义 还是得自己创建RegistrationBean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值