IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot2整合SpringSecurity+Swagger3(源码分析一) -> 正文阅读

[Java知识库]SpringBoot2整合SpringSecurity+Swagger3(源码分析一)

Tomcat容器启动org.apache.catalina.util.LifecycleBase#startInternal,根据当前Spring工厂创建一个ServletContextInitializerBeans对象(其实就是收集各种Servlet元素)
在这里插入图片描述

@SafeVarargs
public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
		Class<? extends ServletContextInitializer>... initializerTypes) {
	this.initializers = new LinkedMultiValueMap<>();
	this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
			: Collections.singletonList(ServletContextInitializer.class);
	addServletContextInitializerBeans(beanFactory);
	addAdaptableBeans(beanFactory);
	List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
			.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
			.collect(Collectors.toList());
	this.sortedList = Collections.unmodifiableList(sortedInitializers);
	logMappings(this.initializers);
}

addServletContextInitializerBeans

org.springframework.boot.web.servlet.ServletContextInitializerBeans#getOrderedBeansOfType(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, java.util.Set<?>)

	private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type,
			Set<?> excludes) {
		String[] names = beanFactory.getBeanNamesForType(type, true, false);
		Map<String, T> map = new LinkedHashMap<>();
		for (String name : names) {
			if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
				T bean = beanFactory.getBean(name, type);
				if (!excludes.contains(bean)) {
					map.put(name, bean);
				}
			}
		}
		List<Entry<String, T>> beans = new ArrayList<>();
		beans.addAll(map.entrySet());
		beans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue()));
		return beans;
	}

在这里插入图片描述
获取所有ServletContextInitializer类型的Bean名称,然后获取Bean,排序并返回。结果如下
在这里插入图片描述
接下来在addServletContextInitializerBeans方法中遍历以上的结果,并根据类型(Servlet、Filter、ServletContextInitializer等类型)进行分组

private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
		ListableBeanFactory beanFactory) {
	if (initializer instanceof ServletRegistrationBean) {
		Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
		addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
	}
	else if (initializer instanceof FilterRegistrationBean) {
		Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
		addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
	}
	else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
		String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
		addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
	}
	else if (initializer instanceof ServletListenerRegistrationBean) {
		EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
		addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
	}
	else {
		addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
				initializer);
	}
}

分组的结果如下,有两个Filter(分别为监控、安全),一个Servlet(DispatchServlet)和一个Servlet上下文初始器(用于actuator)。
在这里插入图片描述

  • dispatcherServletRegistration

配置Spring Boot的SERVLET环境
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration

@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
	DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
			this.webMvcProperties.getServlet().getPath());
	registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
	registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());
	if (this.multipartConfig != null) {
		registration.setMultipartConfig(this.multipartConfig);
	}
	return registration;
}

在这里插入图片描述

  • webMvcMetricsFilter

来源包:spring-boot-actuator-autoconfigure(性能监控)
来源类:org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration

@Bean
public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter(MeterRegistry registry,
		WebMvcTagsProvider tagsProvider) {
	Server serverProperties = this.properties.getWeb().getServer();
	WebMvcMetricsFilter filter = new WebMvcMetricsFilter(registry, tagsProvider,
			serverProperties.getRequestsMetricName(), serverProperties.isAutoTimeRequests());
	FilterRegistrationBean<WebMvcMetricsFilter> registration = new FilterRegistrationBean<>(filter);
	registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
	registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
	return registration;
}

在这里插入图片描述
在这里插入图片描述

  • securityFilterChainRegistration

来源包:spring-boot-autoconfigure(认证授权)
来源类:org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration

Auto-configuration for Spring Security’s Filter. Configured separately from SpringBootWebSecurityConfiguration to ensure that the filter’s order is still configured when a user-provided WebSecurityConfiguration exists.

@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
		SecurityProperties securityProperties) {
	DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
			DEFAULT_FILTER_NAME);
	registration.setOrder(securityProperties.getFilter().getOrder());
	registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
	return registration;
}

在这里插入图片描述
创建Bean的过程首先会实例化一个DispatcherServletRegistrationBean对象,这里并没有复杂的逻辑不过是设置targetBeanName为springSecurityFilterChain。
在这里插入图片描述
然后根据securityProperties设置属性,包括顺序、收集分派类型。
在这里插入图片描述

private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
	if (securityProperties.getFilter().getDispatcherTypes() == null) {
		return null;
	}
	return securityProperties.getFilter().getDispatcherTypes().stream()
			.map((type) -> DispatcherType.valueOf(type.name()))
			.collect(Collectors.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
}

创建流、收集、然后转为EnumSet.实例化对象如下所示
在这里插入图片描述
然后这个类又实现了ApplicationContextAware接口,所以在Bean初始化阶段又会进入到setApplicationContext方法当中。

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
	this.applicationContext = applicationContext;
}

这里的逻辑比较简单,仅仅是设置了Spring上下文对象。

  • servletEndpointRegistrar

来源包:spring-boot-actuator-autoconfigure(性能监控)
来源类:org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration.WebMvcServletEndpointManagementContextConfiguration

ManagementContextConfiguration for servlet endpoints.

@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public static class WebMvcServletEndpointManagementContextConfiguration {

	private final ApplicationContext context;

	public WebMvcServletEndpointManagementContextConfiguration(ApplicationContext context) {
		this.context = context;
	}

	@Bean
	public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties,
			ServletEndpointsSupplier servletEndpointsSupplier) {
		DispatcherServletPath dispatcherServletPath = this.context.getBean(DispatcherServletPath.class);
		return new ServletEndpointRegistrar(dispatcherServletPath.getRelativePath(properties.getBasePath()),
				servletEndpointsSupplier.getEndpoints());
	}

}

在这里插入图片描述
比较简单吗,注册一堆的```EndpointServlet``

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	this.servletEndpoints.forEach((servletEndpoint) -> register(servletContext, servletEndpoint));
}

private void register(ServletContext servletContext, ExposableServletEndpoint endpoint) {
	String name = endpoint.getEndpointId().toLowerCaseString() + "-actuator-endpoint";
	String path = this.basePath + "/" + endpoint.getRootPath();
	String urlMapping = path.endsWith("/") ? path + "*" : path + "/*";
	EndpointServlet endpointServlet = endpoint.getEndpointServlet();
	Dynamic registration = servletContext.addServlet(name, endpointServlet.getServlet());
	registration.addMapping(urlMapping);
	registration.setInitParameters(endpointServlet.getInitParameters());
	logger.info("Registered '" + path + "' to " + name);
}

首先是读取WebEndpointProperties类型Bean获取配置的属性,这些属性的前缀为management.endpoints.web。接下来获取DispatcherServletPath类型的Bean。而这个实现在默认情况下为DispatcherServletRegistrationBean。其实就上面名称为dispatcherServletRegistration的Bean。

在创建Bean的过程中主要是根据传入的basePath和servlet断点设置值而已。
在这里插入图片描述
比较简单,结果如下
在这里插入图片描述

addAdaptableBeans

protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
	MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
	addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
	addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
	for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
		addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
				new ServletListenerRegistrationBeanAdapter());
	}
}

接下来从容器中获取MultipartConfigElement类型Bean,主要是用于文件上传的配置信息。
在这里插入图片描述
然后再次到容器中获取Servlet和Filter,前者只有DispatchServlet(已经处理过了),后者还有其他的一些配置,比如以下这些都是系统默认需要的。
在这里插入图片描述
接下来还会考虑加载EventListener类型Bean.

其中SUPPORTED_TYPES在类加载的时候添加的,这些都属于Servlet规范了。

public class ServletListenerRegistrationBean<T extends EventListener> extends RegistrationBean {

	private static final Set<Class<?>> SUPPORTED_TYPES;

	static {
		Set<Class<?>> types = new HashSet<>();
		types.add(ServletContextAttributeListener.class);
		types.add(ServletRequestListener.class);
		types.add(ServletRequestAttributeListener.class);
		types.add(HttpSessionAttributeListener.class);
		types.add(HttpSessionListener.class);
		types.add(ServletContextListener.class);
		SUPPORTED_TYPES = Collections.unmodifiableSet(types);
	}
    ...
}	

通过以上步骤,收集到的Servlet元素如下所示
在这里插入图片描述
接下来通过流处理(针对每一个map的条目值排序然后通过flatMap转给一个流收集为列表)为列表,然后转为不可修改列表设置为对象属性,并根据日志级别打印日志(org.springframework.boot.web.servlet.ServletContextInitializerBeans为Debug级别)。

List<ServletContextInitializer> sortedInitializers = this.initializers.values()
			.stream()
			.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
			.collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
logMappings(this.initializers);

在这里插入图片描述
最后再回过头来看一下ServletContextInitializerBeans这个类的类型。
在这里插入图片描述
竟然是一个集合,而针对这个集合的迭代就是迭代上面获取的排序好的列表。

@Override
public Iterator<ServletContextInitializer> iterator() {
	return this.sortedList.iterator();
}

@Override
public int size() {
	return this.sortedList.size();
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 11:30:08  更:2021-07-29 11:30:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 4:51:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码