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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章