首頁 > 軟體

SpringBoot原生元件注入實現兩種方式介紹

2022-10-22 14:00:20

原生元件注入SpringBoot,即註冊 Servlet 、Filter、Listener 進入 SpringBoot

一、使用 Servlet API

使用 Servlet API 可以實現原生元件注入,通過在自定義 Servlet 前加入 @WebServlet 註釋,並且在 SpringBoot 啟動類前加入 @ServletComponentScan 註釋,可實現註冊 Servlet

程式碼範例:

1、實現自定義 MyServlet

自定義 Servlet 類:

@WebServlet(urlPatterns = "/my") // 加入 @WebServlet 註釋
public class MyServlet extends HttpServlet { // 注意要繼承 HttpServlet 類
    @Override // 重寫 DoGet 方法
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("haha");
    }
}

專案啟動類:

@ServletComponentScan(basePackages = "com.wanqing.admin") //掃描那個包中有servlet
@SpringBootApplication
public class DemoAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoAdminApplication.class, args);
    }
}

2、實現自定義 MyFilter

@Slf4j
@WebFilter(urlPatterns = {"/css/*", "/images/*"}) // 攔截靜態資源
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        log.info("MyFilter初始化完成");
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("MyFilter工作");
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
        Filter.super.destroy();
        log.info("MyFilter銷燬");
    }
}

3、實現自定義 MyServletContextListener

@WebListener
@Slf4j
public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyServletContextListener 監聽到專案初始化完成");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyServletContextListener 監聽到專案銷燬");
    }
}

二、使用 RegistrationBean 的方式注入原生元件

通過編寫 MyRegistConfig 設定類,返回 RegistrationBean 的方式實現元件的注入,與上一種方式的區別在於,這種方式不需要給 自定義 Servlet 類寫 @WebServlet 註釋。

注意點:要記得使用 @Bean 註釋將 ServletRegistrationBean 註冊到容器中。

程式碼範例:

自定義 MyRegistConfig 設定類,註冊 myServlet 元件,返回 ServletRegistrationBean 物件 (物件引數為自定義的 myServlet 物件範例)

myFilter 及myListener 的實現方式同理

@Configuration
public class MyRegistConfig {
    @Bean
    public ServletRegistrationBean myServlet(){
        MyServlet myServlet = new MyServlet();
        return new ServletRegistrationBean(myServlet, "/my","/my02");
    }
    @Bean
    public FilterRegistrationBean myFilter(){
        MyFilter filter = new MyFilter();
        //return new FilterRegistrationBean(filter, myServlet()); // 攔截myServlet()的路徑
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter);
        filterRegistrationBean.addUrlPatterns("/my","/css/*");
        return filterRegistrationBean;
    }
    @Bean
    public ServletListenerRegistrationBean myListener(){
        MyServletContextListener myServletContextListener = new MyServletContextListener();
        return new ServletListenerRegistrationBean(myServletContextListener);

    }
}

拓展:為什麼攔截器不攔截 我們自定義的 MyServlet 請求?

分析 DispatcherServlet 如何註冊進入容器中,從 DispatcherServletAutoConfiguration 類開始

容器中自動設定了 DispatcherServlet 元件,其屬性繫結到 WebMvcProperties 中,對應的組態檔是 spring.mvc

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) // 註冊 DispatcherServlet  元件
		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
			return dispatcherServlet;
		}

通過 ServletRegistrationBean < DispatcherServlet > 機制(DispatcherServletRegistrationBean.class)將 DispatcherServlet 原生的 Servlet 元件設定進來

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
					webMvcProperties.getServlet().getPath()); // 拿到預設對映路徑為 / 路徑
			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
			multipartConfig.ifAvailable(registration::setMultipartConfig);
			return registration;
		}

拿到預設對映路徑 /

WebMvcProperties.class 中設定

使用 Tomcat 做原生 Servlet 開發,如果多個 Servlet 都能處理到同一層路徑,是精確優先原則,例如:

A:/my/

B: /my/1

傳送 /my/1 請求 B處理,而傳送 /my/2 請求 A 處理

結論 : 來到 /my 不經過 / —— 精確匹配 /my 直接經 Tomcat 寫出響應,不經過 SpringMVC 的一系列流程,因此不被攔截器攔截,如下圖所示:

到此這篇關於SpringBoot原生元件注入實現兩種方式介紹的文章就介紹到這了,更多相關SpringBoot原生元件注入內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com