/** * ServletContainerInitializers (SCIs) are registered via an entry in the * file META-INF/services/javax.servlet.ServletContainerInitializer that must be * included in the JAR file that contains the SCI implementation. * <p> * SCI processing is performed regardless of the setting of metadata-complete. * SCI processing can be controlled per JAR file via fragment ordering. If * absolute ordering is defined, then only the JARs included in the ordering * will be processed for SCIs. To disable SCI processing completely, an empty * absolute ordering may be defined. * <p> * SCIs register an interest in annotations (class, method or field) and/or * types via the {@link javax.servlet.annotation.HandlesTypes} annotation which * is added to the class. * * @since Servlet 3.0 */ publicinterfaceServletContainerInitializer {
/** * Receives notification during startup of a web application of the classes * within the web application that matched the criteria defined via the * {@link javax.servlet.annotation.HandlesTypes} annotation. * * @param c The (possibly null) set of classes that met the specified * criteria * @param ctx The ServletContext of the web application in which the * classes were discovered * * @throws ServletException If an error occurs */ voidonStartup(Set<Class<?>> c, ServletContext ctx)throws ServletException; }
观察SpringServletContainerInitializer可以发现,其就是通过标注的注解获得所有Spring相关的WebApplicationInitializer初始化器,将其加入到自身的onstartUp()方法中进行执行,最终达到加载不同初始化器中配置的类到servletContext容器当中。官方onStartup()方法解释如下:*If no WebApplicationInitializer implementations are found on the classpath, this method is effectively a no-op. An INFO-level log message will be issued notifying the user that the ServletContainerInitializer has indeed been invoked but that no WebApplicationInitializer implementations were found.Assuming that one or more WebApplicationInitializer types are detected, they will be instantiated (and sorted if the @@Order annotation is present or the Ordered interface has been implemented). Then the WebApplicationInitializer.onStartup(ServletContext) method will be invoked on each instance, delegating the ServletContext such that each instance may register and configure servlets such as Spring’s DispatcherServlet, listeners such as Spring’s ContextLoaderListener, or any other Servlet API componentry such as filters.*大概意思是,如果在类路径没有找WebApplicationInitializer 的实现类,那么这个方法实质上没有起到什么作用,就会发送日志给用户,告知这个ServletContainerInitializer 初始化器已经实际执行到这里,但是没有找到WebApplicationInitializer的相关实现类。如果类路径存在相关实现类,那么这些实现类会被加载到方法中,进行实例化,之后并且按照@Order注解标注的顺序进行排序,最后遍历每一个初始化器执行其中的初始化方法。
//存储所有从方法参数获得的初始化器 List<WebApplicationInitializer> initializers = Collections.emptyList(); if (webAppInitializerClasses != null) { initializers = newArrayList<>(webAppInitializerClasses.size()); for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { //创建每个初始化器的实例 initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance()); } catch (Throwable ex) { thrownewServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } }
if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; }
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); //排序所有的初始化器 AnnotationAwareOrderComparator.sort(initializers); //遍历初始化器集合,按顺序进行加载 for (WebApplicationInitializer initializer : initializers) { //执行每一个Spring初始化器的初始化方法(向上下文中存入相应对象) initializer.onStartup(servletContext); } }
}
那么当容器初始化的时候就会注入Spring的初始化器。根据Spring初始化启动器加载又会加载@HandlesTypes标注的所有相应的WebApplicationInitializers。那么这里我们关注SpringSecurity中的这个初始化器AbstractSecurityWebApplicationInitializer,根据第一行Registers the DelegatingFilterProxy to use the springSecurityFilterChain before any other registered Filter说到:会在注册其他过滤器前,实际会注册DelegatingFilterProxy来使用springSecurityFilterChain。
/** * 创建实例时,假设Spring安全配置是通过此类之外的类进行加载。 * AbstractSecurityWebApplicationInitializer类实际上是在SpringServletContainerInitializer使用反射工具加载的 ReflectionUtils.accessibleConstructor(waiClass).newInstance());因此调用的是当前无参构造 * Creates a new instance that assumes the Spring Security configuration is loaded by * some other means than this class. For example, a user might create a * {@link ContextLoaderListener} using a subclass of * {@link AbstractContextLoaderInitializer}. * * @see ContextLoaderListener */ protectedAbstractSecurityWebApplicationInitializer() { this.configurationClasses = null; }
/** * 使用指定的类实例化当前初始化器 * Creates a new instance that will instantiate the {@link ContextLoaderListener} with * the specified classes. * @param configurationClasses */ protectedAbstractSecurityWebApplicationInitializer(Class<?>... configurationClasses) { this.configurationClasses = configurationClasses; }
//DelegatingFilterProxy类 //初始化过滤器 @Override protectedvoidinitFilterBean()throws ServletException { synchronized (this.delegateMonitor) { if (this.delegate == null) { // If no target bean name specified, use filter name. if (this.targetBeanName == null) { this.targetBeanName = getFilterName(); } // Fetch Spring root application context and initialize the delegate early, // if possible. If the root application context will be started after this // filter proxy, we'll have to resort to lazy initialization. WebApplicationContextwac= findWebApplicationContext(); if (wac != null) { this.delegate = initDelegate(wac); } } } }
//VirtualFilterChain类 /** * Internal {@code FilterChain} implementation that is used to pass a request through * the additional internal list of filters which match the request. */ privatestaticfinalclassVirtualFilterChainimplementsFilterChain {
//WebSecurityConfiguration @Autowired(required = false) publicvoidsetFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception { //创建webSecurity实例对象,使用Spring容器初始化 this.webSecurity = objectPostProcessor.postProcess(newWebSecurity(objectPostProcessor)); if (this.debugEnabled != null) { this.webSecurity.debug(this.debugEnabled); } //对其实现的所有的webSecurity进行排序 webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE); IntegerpreviousOrder=null; ObjectpreviousConfig=null; for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) { Integerorder= AnnotationAwareOrderComparator.lookupOrder(config); if (previousOrder != null && previousOrder.equals(order)) { thrownewIllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too."); } previousOrder = order; previousConfig = config; } //收集所有的WebSecurityConfigurer配置对象,排序后的所有WebSecurityConfigurer依次添加到WebSecurity中 for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) { this.webSecurity.apply(webSecurityConfigurer); } //保存排序后的所有WebSecurityConfigurer this.webSecurityConfigurers = webSecurityConfigurers; }
AbstractConfiguredSecurityBuilder中的方法:
//AbstractConfiguredSecurityBuilder类
/** * Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder} overriding any * {@link SecurityConfigurer} of the exact same class. Note that object hierarchies * are not considered. * @param configurer * @return the {@link SecurityConfigurerAdapter} for further customizations * @throws Exception */ public <C extendsSecurityConfigurer<O, B>> C apply(C configurer)throws Exception { //调用方法将配置进行添加 add(configurer); return configurer; }
/** * 根据配置类状态进行增加 * Adds {@link SecurityConfigurer} ensuring that it is allowed and invoking * {@link SecurityConfigurer#init(SecurityBuilder)} immediately if necessary. * @param configurer the {@link SecurityConfigurer} to add */ @SuppressWarnings("unchecked") private <C extendsSecurityConfigurer<O, B>> voidadd(C configurer) { Assert.notNull(configurer, "configurer cannot be null"); Class<? extendsSecurityConfigurer<O, B>> clazz = (Class<? extendsSecurityConfigurer<O, B>>) configurer .getClass(); synchronized (this.configurers) { //当前是否已经配置过,配置过不进行配置 if (this.buildState.isConfigured()) { thrownewIllegalStateException("Cannot apply " + configurer + " to already built object"); } List<SecurityConfigurer<O, B>> configs = null; if (this.allowConfigurersOfSameType) { configs = this.configurers.get(clazz); } configs = (configs != null) ? configs : newArrayList<>(1); configs.add(configurer); this.configurers.put(clazz, configs); if (this.buildState.isInitializing()) { //判断其需要进行初始化的配置对象SecurityConfigurer ,将其加入configurersAddedInInitializing //private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>(); this.configurersAddedInInitializing.add(configurer); } } }