SpringSecurity初始化的本质

发布于:2025-02-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、对SpringSecurity初始化的几个疑问

  通过前面第一次请求访问的分析我们明白了一个请求就来后的具体处理流程

image.png

  对于一个请求到来后会通过FilterChainProxy来匹配一个对应的过滤器链来处理该请求。那么这里我们就有几个疑惑。

  1. FilterChainProxy什么时候创建的?
  2. 过滤器链和对应的过滤器什么时候创建的?
  3. 怎么把自定义的过滤器添加到过滤器链中?
  4. 请求和过滤器的匹配规则是什么?

二、解析配置文件的过程

1.解析前的处理

  接下来我们来分析下Spring初始化的时候是如果解析SpringSecurity的配置文件的,并且存储在哪了?同时来解释我们上面的几个疑问。

首先系统启动的时候会触发在 web.xml中配置的ContextLoaderListener监听器

image.png

然后会执行对应的initWebApplicationContext方法

image.png

然后进入configureAndRefreshWebApplicationContext方法中。

image.png

然后进入refresh()方法

	@Override
	public void refresh() throws BeansException, IllegalStateException {
   
		synchronized (this.startupShutdownMonitor) {
   
			// Prepare this context for refreshing.
			/**
			 * 前戏,做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
			 * 5、准备监听器和事件的集合对象,默认为空的集合
			 */

			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 创建容器对象:DefaultListableBeanFactory
			// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// beanFactory的准备工作,对各种属性进行填充
			prepareBeanFactory(beanFactory);

			try {
   
				// Allows post-processing of the bean factory in context subclasses.
				// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 调用各种beanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件监听多路广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 留给子类来初始化其他的bean
				onRefresh();

				// Check for listener beans and register them.
				// 在所有注册的bean中查找listener bean,注册到消息广播器中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 初始化剩下的单实例(非懒加载的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
				finishRefresh();
			}

			catch (BeansException ex) {
   
				if (logger.isWarnEnabled()) {
   
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
				destroyBeans();

				// Reset 'active' flag.
				// 重置active标志
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
   
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

我们要看配置文件的加载解析需要进入obtainFreshBeanFactory()方法中。

image.png

再继续进入

image.png

继续

image.png

这块会比较绕,直接截图进关键代码

image.png

一步

image.png

两步

image.png

三步

image.png

慢慢进入

image.png

image.png

image.png

image.png

image.png

开始具体的配置文件的加载解析

image.png

2.解析过程

  在上面的步骤基础上我们进入registerBeanDefinitions方法中来看看是如何具体实现配置文件的解析操作

image.png

然后进入registerBeanDefinitions方法中

image.png

继续

image.png

进入parseBeanDefinitions方法中,就会开始对应的节点解析。

image.png

parseDefaultElement方法会完成Spring中提供的默认方法解析,具体如下: