说在前面
前期回顾
sharding-jdbc源码解析 更新完毕
spring源码解析 更新完毕
spring-mvc源码解析 更新完毕
spring-tx源码解析 更新完毕
spring-boot源码解析 更新完毕
rocketmq源码解析 更新完毕
dubbbo源码解析 更新完毕
netty源码解析 更新完毕
spring源码架构更新完毕
spring-mvc源码架构更新完毕
springboot源码架构更新中
github https://github.com/tianheframe
sharding-jdbc源码解析 更新完毕
rocketmq源码解析 更新完毕
seata 源码解析 更新完毕
dubbo 源码解析 更新完毕
netty 源码解析 更新完毕
源码解析
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext WebApplicationContext,可用于从包含的EmbeddedServletContainerFactory bean引导自身。通过在ApplicationContext本身中搜索单个EmbeddedServletContainerFactory bean,该上下文将创建、初始化和运行EmbeddedServletContainer。EmbeddedServletContainerFactory可以免费使用标准Spring概念(例如依赖项注入、生命周期回调和属性占位符变量)。
此外,在上下文中定义的任何Servlet或过滤器bean都将自动注册到嵌入式Servlet容器中。对于单个Servlet bean,将使用'/'映射。如果找到多个Servlet bean,则使用小写bean名作为映射前缀。任何名为“dispatcherServlet”的Servlet都将始终映射到“/”。过滤器bean将映射到所有url('/*')。对于更高级的配置,上下文可以定义实现ServletContextInitializer接口的bean(通常是ServletRegistrationBeans和/或FilterRegistrationBeans)。为了防止双重注册,使用ServletContextInitializer bean将禁用自动Servlet和过滤器bean注册。尽管可以直接使用这个上下文,但是大多数开发人员应该考虑使用AnnotationConfigEmbeddedWebApplicationContext或XmlEmbeddedWebApplicationContext变体。
public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
DispatcherServlet bean名称的常量值。具有此名称的Servlet bean被认为是“主”Servlet,默认情况下会自动给出“/”的映射。要更改默认行为,可以使用ServletRegistrationBean或其他bean名称。
private volatile EmbeddedServletContainer embeddedServletContainer;
embeddedServletContainer
private ServletConfig servletConfig;
servletConfig
private String namespace;
namespace
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 添加WebApplicationContextServletContextAwareProcessor beanbeanPostProcessor beanFactory.addBeanPostProcessor( new WebApplicationContextServletContextAwareProcessor(this));// 忽略ServletContextAware依赖类型 beanFactory.ignoreDependencyInterface(ServletContextAware.class);// 注册application scopes registerWebApplicationScopes(); }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#registerWebApplicationScopes 注册application scope
private void registerWebApplicationScopes() { ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes( getBeanFactory()); WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory()); existingScopes.restore(); }
org.springframework.web.context.support.WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) 注册"request", "session", "globalSession" scopes
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { registerWebApplicationScopes(beanFactory, null); }
org.springframework.web.context.support.WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, javax.servlet.ServletContext) 注册web scopes
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) { beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false)); beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true)); if (sc != null) { ServletContextScope appScope = new ServletContextScope(sc); beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register as ServletContext attribute, for ContextCleanupListener to detect it. sc.setAttribute(ServletContextScope.class.getName(), appScope); } beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); if (jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } }
注册request、session、golalSession、application的scopes
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.ExistingWebApplicationScopes#restore 重置application scopes
public void restore() { for (Map.Entry<String, Scope> entry : this.scopes.entrySet()) { if (logger.isInfoEnabled()) { logger.info("Restoring user defined scope " + entry.getKey()); } this.beanFactory.registerScope(entry.getKey(), entry.getValue()); } }
@Override public final void refresh() throws BeansException, IllegalStateException { try {// 初始化spring上下文 super.refresh(); } catch (RuntimeException ex) { stopAndReleaseEmbeddedServletContainer(); throw ex; } }
刷新上下文,出现异常停止servlet容器,org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#stopAndReleaseEmbeddedServletContainer
private void stopAndReleaseEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; if (localContainer != null) { try { localContainer.stop(); this.embeddedServletContainer = null; } catch (Exception ex) { throw new IllegalStateException(ex); } } }
@Override protected void onRefresh() { super.onRefresh(); try { createEmbeddedServletContainer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to starbedded container", ex); } }
刷新上下文事件,org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#createEmbeddedServletContainer 创建集成的servlet容器
private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer;// 获得servletContext ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) {// 获得EmbeddedServletContainerFactory EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); this.embeddedServletContainer = containerFactory// 获得ServletContextInitializer .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try {// servletcontext的启动方法 getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } }// 初始化配置 initPropertySources(); }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory返回应用于创建嵌入式servlet容器的EmbeddedServletContainerFactory。默认情况下,此方法在上下文中搜索合适的bean。
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { // Use bean names so that we don't consider the hierarchy 使用bean名称,这样我们就不会考虑层次结构// 根据bean类型获取bean的类型实现的beanNames String[] beanNames = getBeanFactory() .getBeanNamesForType(EmbeddedServletContainerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to missing " + "EmbeddedServletContainerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to multiple " + "EmbeddedServletContainerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], EmbeddedServletContainerFactory.class); }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#getSelfInitializer返回ServletContextInitializer
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() { return new ServletContextInitializer() { @Override public void onStartup(ServletContext servletContext) throws ServletException {// 初始化servletContext selfInitialize(servletContext); } }; }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#selfInitialize
private void selfInitialize(ServletContext servletContext) throws ServletException { prepareEmbeddedWebApplicationContext(servletContext);// 注册application scope registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext); for (ServletContextInitializer beans : getServletContextInitializerBeans()) {// 执行servletContext初始化器的启动方法 beans.onStartup(servletContext); } }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#prepareEmbeddedWebApplicationContext使用给定的完全加载的ServletContext准备WebApplicationContext。这个方法通常从ServletContextInitializer.onStartup(ServletContext)调用,它与ContextLoaderListener通常提供的功能类似。
protected void prepareEmbeddedWebApplicationContext(ServletContext servletContext) { Object rootContext = servletContext.getAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); if (rootContext != null) { if (rootContext == this) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ServletContextInitializers!"); } return; } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring embedded WebApplicationContext"); try { servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this); if (logger.isDebugEnabled()) { logger.debug( "Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); }// 设置servletContext setServletContext(servletContext); if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - getStartupDate(); logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#registerApplicationScope 注册application scope
private void registerApplicationScope(ServletContext servletContext) { ServletContextScope appScope = new ServletContextScope(servletContext); getBeanFactory().registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register as ServletContext attribute, for ContextCleanupListener to detect it. servletContext.setAttribute(ServletContextScope.class.getName(), appScope); }
@Override protected void finishRefresh() {// 执行上下文刷新完成逻辑 super.finishRefresh();// 启动集成的servlet容器 EmbeddedServletContainer localContainer = startEmbeddedServletContainer(); if (localContainer != null) {// 发布集成servlet容器初始化完毕事件 publishEvent( new EmbeddedServletContainerInitializedEvent(this, localContainer)); } }
完成上下文刷新
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#startEmbeddedServletContainer servlet容器启动
private EmbeddedServletContainer startEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; if (localContainer != null) {// 启动servlet容器 localContainer.start(); } return localContainer; }
@Override protected void onClose() {// 上下文关闭处理 super.onClose();// 停止servlet容器 stopAndReleaseEmbeddedServletContainer(); }
上下文关闭处理,org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#stopAndReleaseEmbeddedServletContainer
private void stopAndReleaseEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; if (localContainer != null) { try { localContainer.stop(); this.embeddedServletContainer = null; } catch (Exception ex) { throw new IllegalStateException(ex); } } }
关闭servlet容器
org.springframework.boot.context.embedded.XmlEmbeddedWebApplicationContext EmbeddedWebApplicationContext从XML文档中获取配置,XmlBeanDefinitionReader可以理解它。注意:对于多个配置位置,后面的bean定义将覆盖前面加载的文件中定义的配置位置。可以利用这一点,通过额外的XML文件故意覆盖某些bean定义。
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
XmlBeanDefinitionReader
public XmlEmbeddedWebApplicationContext(Resource... resources) { load(resources); refresh(); }
创建一个新的XmlEmbeddedWebApplicationContext,从给定资源加载bean定义并自动刷新上下文。加载BeanDefinition并刷新上下文
org.springframework.boot.context.embedded.XmlEmbeddedWebApplicationContext#load(org.springframework.core.io.Resource...)从给定的XML资源加载bean定义。
public final void load(Resource... resources) { this.reader.loadBeanDefinitions(resources); }
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#refresh 刷新上下文,出现异常停止servlet容器
@Override public final void refresh() throws BeansException, IllegalStateException { try {// 初始化spring上下文 super.refresh(); } catch (RuntimeException ex) { stopAndReleaseEmbeddedServletContainer(); throw ex; } }
xml方式加载BeanDefinition、刷新上下文逻辑这里不做详细介绍,可以查看spring源码解析相关的文章
@Override protected void onRefresh() { super.onRefresh(); try { createEmbeddedServletContainer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to starbedded container", ex); } }
创建集成的servlet容器并初始化servlet容器初始化器
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#createEmbeddedServletContainer
private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer;// 获得servletContext ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) {// 获得EmbeddedServletContainerFactory EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); this.embeddedServletContainer = containerFactory// 获得ServletContextInitializer .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try {// servletcontext的启动方法 getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } }// 初始化配置 initPropertySources(); }
public final void load(Resource... resources) { this.reader.loadBeanDefinitions(resources); }
从给定的XML资源加载bean定义。加载BeanDefinition这里不做详细介绍,可以查看spring源码解析系列相关文章
org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext EmbeddedWebApplicationContext接受带注释的类作为输入—特别是@Configuration -带注释的类,但是也可以使用javax接受普通的@Component类和JSR-330兼容的类。注入注解。允许逐个注册类(指定类名作为配置位置)以及类路径扫描(指定基本包作为配置位置)。注意:对于多个@Configuration类,后面的@Bean定义将覆盖前面加载的文件中定义的类。可以利用这一点,通过额外的配置类故意覆盖某些bean定义。
private final AnnotatedBeanDefinitionReader reader;
基于注解的BeanDefinition阅读器
private final ClassPathBeanDefinitionScanner scanner;
基于报名扫描的BeanDefinition扫描器
private Class>[] annotatedClasses;
基于注解的配置类
private String[] basePackages;
包名
public AnnotationConfigEmbeddedWebApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
创建一个新的AnnotationConfigEmbeddedWebApplicationContext,它需要通过注册调用填充,然后手动刷新。
public AnnotationConfigEmbeddedWebApplicationContext(Class>... annotatedClasses) { this(); register(annotatedClasses); refresh(); }
创建一个新的AnnotationConfigEmbeddedWebApplicationContext,从给定的带注释的类派生bean定义,并自动刷新上下文。
注册@Configuration配置类,刷新上下文,出现异常停止servlet容器
public AnnotationConfigEmbeddedWebApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); }
扫描指定包的BeanDefinition刷新上下文
public final void register(Class>... annotatedClasses) { this.annotatedClasses = annotatedClasses; Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); }
注册一个或多个要处理的带注释的类。注意,必须调用refresh(),以便上下文能够完全处理新类。对#register的调用是幂等的;多次添加同一个带注释的类不会产生额外的效果。
public final void scan(String... basePackages) { this.basePackages = basePackages; Assert.notEmpty(basePackages, "At least one base package must be specified"); }
执行基于包名扫描的BeanDefinition扫描器的包名
@Override protected void prepareRefresh() {// 清空包路径BeanDefinition扫描器的元数据缓存 this.scanner.clearCache();// 刷新上下文预处理逻辑 super.prepareRefresh(); }
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); if (this.basePackages != null && this.basePackages.length > 0) {// 扫描包名指定的BeanDefinition this.scanner.scan(this.basePackages); } if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {// 注册@Configuration配置类 this.reader.register(this.annotatedClasses); } }
添加beanPostProcessor、注册web scopes,扫描指定包名的BeanDefinition,注册@Configuration配置类
说在最后
本次解析仅代表个人观点,仅供参考。
扫码进入技术微信群
钉钉技术群qq技术群