• springboot 自动注入servlet原理


    前置内容: servlet的多种注册方式

    SpringBoot启用 ServletContainerInitializer

    ServletContainerInitializer-SPI

    SPI部分内容参照 servlet的多种注册方式

    开启SPI

    默认情况下,springboot 使用 embedded-tomcat,没有启用ServletContainerInitializer,这就需要我们做改造。

    pom.xml

     <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.bootgroupId>
                        <artifactId>spring-boot-starter-tomcatartifactId>
                    exclusion>
                exclusions>
            dependency>
    
            
            <dependency>
                <groupId>javax.servletgroupId>
                <artifactId>javax.servlet-apiartifactId>
                <version>3.1.0version>
                <scope>providedscope>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    App.java 继承 SpringBootServletInitializer

    @SpringBootApplication
    public class App extends SpringBootServletInitializer {
    
     /*   public static void main(String[] args) {
            SpringApplication.run(App.class, args);
        }
    */
    
    /*    @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(App.class);
        }*/
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    springboot SPI

    在这里插入图片描述

    增加Filter配置类

    @Configuration
    public class SpringFilterConfiguration {
    
        @Bean
        public FilterRegistrationBean<SpringFilter1> SpringFilter1() {
            FilterRegistrationBean<SpringFilter1> registrationBean = new FilterRegistrationBean<>();
            registrationBean.setFilter(new SpringFilter1());
            registrationBean.setName("springfilter11");
            registrationBean.addUrlPatterns("/*");
            registrationBean.setOrder(11);
            return registrationBean;
        }
    
        @Bean
        public FilterRegistrationBean<SpringFilter2> SpringFilter2() {
            FilterRegistrationBean<SpringFilter2> registrationBean = new FilterRegistrationBean<>();
            registrationBean.setFilter(new SpringFilter2());
            registrationBean.setName("springfilter22");
            registrationBean.addUrlPatterns("/*");
            registrationBean.setOrder(22);
            return registrationBean;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    源码分析

    1. SpringServletContainerInitializer

    @HandlesTypes(WebApplicationInitializer.class) //lookup 实现WebApplicationInitializer的类
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
    	@Override
    	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
    			throws ServletException {
    		List<WebApplicationInitializer> initializers = new ArrayList<>(webAppInitializerClasses.size());
    
    		for (Class<?> waiClass : webAppInitializerClasses) {
    			initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
    		}
    
    		AnnotationAwareOrderComparator.sort(initializers);
    		for (WebApplicationInitializer initializer : initializers) { //  2. 此时值为App.class
    			initializer.onStartup(servletContext); 
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.App

    类图

    App为我们的主类,它的泪如如下。

    在这里插入图片描述

    3.SpringBootServletInitializer.onStartup(servletContext)

    程序的最终入口就在此了。

    public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
    	
    	@Override
    	public void onStartup(ServletContext servletContext) throws ServletException {
    		WebApplicationContext rootApplicationContext = createRootApplicationContext(servletContext); // 3.1
    		if (rootApplicationContext != null) {
    			servletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext)); //3.2
    		}
    	}
    
    	//3.1
    	protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
    		SpringApplicationBuilder builder = createSpringApplicationBuilder(); // new SpringApplicationBuilder()
    		builder.main(getClass()); // getClass() == App.class
    		
    		//parent部分略....
    
    		builder.initializers(new ServletContextApplicationContextInitializer(servletContext));  //3.1.1
    		builder.contextFactory((webApplicationType) -> new AnnotationConfigServletWebServerApplicationContext()); //3.1.2 factory 直接返回new AnnotationConfigServletWebServerApplicationContext(); extends ServletWebServerApplicationContext
    		builder = configure(builder); //do nothing 
    		builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext)); //3.1.3
    		SpringApplication application = builder.build(); // 返回 SpringApplication
    		application.addPrimarySources(Collections.singleton(getClass())); //3.1.4
    		
    		application.setRegisterShutdownHook(false);
    		return run(application);
    	}
    
    	protected WebApplicationContext run(SpringApplication application) {
    		return (WebApplicationContext) application.run(); //执行 SpringApplication.run()
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    4. SpringApplication.run()

    SpringApplication.run()的逻辑不再赘述, 最终会调用AbstractApplicationContext.onRefresh(),而此时的ApplicationContext的具体实现类为AnnotationConfigServletWebServerApplicationContext

    public class SpringApplication {
    	private List<ApplicationContextInitializer<?>> initializers;		 //3.1.1
    	private List<ApplicationListener<?>> listeners;				//3.1.3
    	private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT; //3.1.2
    	private Set<Class<?>> primarySources;  //3.1.4
    
    	public ConfigurableApplicationContext run(String... args) {
    		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    		ConfigurableApplicationContext context = null;
    		configureHeadlessProperty();
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    		configureIgnoreBeanInfo(environment);
    		Banner printedBanner = printBanner(environment);
    		context = createApplicationContext(); // applicationContextFactory.create()//3.1.2 return AnnotationConfigServletWebServerApplicationContext();
    		context.setApplicationStartup(this.applicationStartup);
    		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    		refreshContext(context); // ConfigurableApplicationContext.refresh();   ---> AbstractApplicationContext.onRefresh();
    		afterRefresh(context, applicationArguments);
    		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    		if (this.logStartupInfo) {
    			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
    		}
    		listeners.started(context, timeTakenToStartup);
    		callRunners(context, applicationArguments);
    		
    		return context;
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    5.AnnotationConfigServletWebServerApplicationContext.onRefresh()

    类图

    在这里插入图片描述

    ServletWebServerApplicationContext.onRefresh()

    public class ServletWebServerApplicationContext extends GenericWebApplicationContext
    		implements ConfigurableWebServerApplicationContext {
    	@Override
    	protected void onRefresh() {
    		super.onRefresh();
    		createWebServer(); // factory.getWebServer(getSelfInitializer());
    	}
    
    
    	private void selfInitialize(ServletContext servletContext) throws ServletException {
    		prepareWebApplicationContext(servletContext);
    		registerApplicationScope(servletContext);
    		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
    		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {  beanFactory.getBeanNamesForType(ServletContextInitializer.class);
    			beans.onStartup(servletContext); //6
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    6.ServletContextInitializer.onStartup

    类图

    在这里插入图片描述

    AbstractFilterRegistrationBean.addRegistration()

    //6. FilterRegistrationBean -> AbstractFilterRegistrationBean -> DynamicRegistrationBean  -> RegistrationBean
    public abstract class AbstractFilterRegistrationBean<T extends Filter> extends DynamicRegistrationBean<Dynamic> {
    
    	@Override
    	protected Dynamic addRegistration(String description, ServletContext servletContext) {
    		Filter filter = getFilter();
    		return servletContext.addFilter(getOrDeduceName(filter), filter);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    智慧城市新篇章:数字孪生的力量与未来
    你的微信版本过低,无法正常使用此小程序,请更新微信到最新版本。
    U-BOOT小全(三):SPL框架
    自动化学报格式 Overleaf 在线使用 【2023最新教程】
    传播问卷调查数据不够?自己生成假数据!
    Python中tuple()函数的用法
    TextBox文本框与PasswordBox密码框水印
    文艺复兴科技
    NSSCTF第12页(3)
    【无标题】
  • 原文地址:https://blog.csdn.net/it_freshman/article/details/126012413