Java源码(三)SpringBoot Web容器应用上下文

news2024/11/15 23:52:19

思维导图



本文主要分析ServletWebServerApplicationContext源码
SpringBoot Web容器应用上下文(这是个人的翻译, 如有不足之处还望指出, 大佬勿喷!!!)

1.自我思考及复盘

备注: 自我思考及复盘是为了养成带着问题阅读源码及阅读完源码后总结,是个人的学习及实践见解, 如有不足之处还望指出, 大佬勿喷!!!

1.1 自我思考

  1. what-是什么?
    servlet web 服务器(如tomcat)的应用上下文
  2. why-为什么,作用?
    因为要支持spring boot的内嵌即外部web服务应用上下文加载、初始化、刷新、使用、停止等
  3. how–如何工作的?原理
  • 继承、实现应用上下文初始化、刷新、使用、停止方法
    • 准备刷新Servlet 服务器上下文环境,初始化Servlet 服务器 beanfactory,加载其beanfactory定义信息
    • 系统配置Servlet 服务器 beanfactory,并激活BeanFactoryPostProcessors
    • 注册相关的BeanPostProcessors,初始化及注册相关的MessageSource、时间广播器、事件监听器
    • 热加载Servlet 服务器 单例bean,完成其刷新过程
    • SpringBoot容器使用Servlet 服务器,停止调用销毁方法。
  1. 如果是我,将会如何设计?使用到哪些设计模式?
  • 将使用模板方法:针对不同的Servlet 服务器套用对应模板,重写模板方法
  • 策略模式:根据内嵌还是外置的服务器去调用对应的加载运行方法

1.2 复盘

  1. 用到哪些设计模式?
  • 其中DefaultSingletonBeanRegistry有用到单例模式(双重检测)获取Bean,代码中未列出,补充一下:


// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName){
    //参数true设置标识允许早期依赖
    return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //如果为空,则锁定全局变量并进行处理。
        synchronized (this.singletonObjects) {
            //如果此bean正在加载,则不处理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {  
                //当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //调用预先设定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中,earlysingletonObjects和singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

  • 在AnnotationConfigServletWebServerApplicationContext有用到策略模式及适配器模式:详见下文
    SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext


2.概述

  • SpringApplication#createApplicationContext() 方法,根据不同的 Web 应用类型,创建不同的 Spring 容器,如下:

	// SpringApplication.java
	
	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		// 根据 webApplicationType 类型,获得 ApplicationContext 类型
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		// 创建 ApplicationContext 对象
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
  • 本文主要分享SERVLET 类型对应的 Spring 容器类型 AnnotationConfigServletWebServerApplicationContext 类,类图如下:

在这里插入图片描述
(蓝色实线是类继承关系;绿色虚线是接口实现关系;绿色实线是接口与接口之间关系–可以用extends词)




3.ServletWebServerApplicationContext

实现 ConfigurableWebServerApplicationContext 接口,获得管理 WebServer 的能力;继承 GenericWebApplicationContext 类,Spring Boot 使用 Servlet Web 服务器的 ApplicationContext 实现类。

核心方法refresh()向上继承了AbstractApplicationContext#refresh()方法


	// AbstractApplicationContext.java
	// `#refresh()` 方法
	
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
		
				.......
				
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);  // <1>
				
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh(); // <2>

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh(); // <3>
			}

			........
	}

3.1 #refresh() 方法

备注:#refresh() 方法本质还是调用上面AbstractApplicationContext的核心#refresh(),这里另外做了异常处理

3.1.1 初始化Spring 容器

// ServletWebServerApplicationContext.java

@Override
public final void refresh() throws BeansException, IllegalStateException {
	try {
		super.refresh();
	} catch (RuntimeException ex) {
		// <X> 如果发生异常,停止 WebServer
		stopAndReleaseWebServer();
		throw ex;
	}
}

3.1.2 #stopAndReleaseWebServer()方法停止 WebServer

// ServletWebServerApplicationContext.java
    
private void stopAndReleaseWebServer() {
    // 获得 WebServer 对象,避免被多线程修改了
    WebServer webServer = this.webServer;
    if (webServer != null) {
        try {
            // 停止 WebServer 对象
            webServer.stop();
            // 置空 webServer
            this.webServer = null;
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
    }
}

3.2 #postProcessBeanFactory(beanFactory)方法

覆写 #postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 方法,代码如下:

	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// <1.1> 注册 WebApplicationContextServletContextAwareProcessor
		beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
		// <1.2> 忽略 ServletContextAware 接口。
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		// <2> 注册 ExistingWebApplicationScopes
		registerWebApplicationScopes();
	}

3.2.1 <1.1> 处,注册 WebApplicationContextServletContextAwareProcessor 。

  • WebApplicationContextServletContextAwareProcessor 的作用,主要是处理实现 ServletContextAware 接口的 Bean 。
  • 在这个处理类,初始化这个 Bean 中的 ServletContext 属性。
  • 这样在实现 ServletContextAware 接口的 Bean 中就可以拿到 ServletContext 对象了,Spring 中 Aware 接口就是这样实现的。
  • 这样,就可以从 webApplicationContext 中,获得 ServletContext 和 ServletConfig 属性。
    代码如下:
// WebApplicationContextServletContextAwareProcessor.java

public class WebApplicationContextServletContextAwareProcessor extends ServletContextAwareProcessor {

	private final ConfigurableWebApplicationContext webApplicationContext;

	public WebApplicationContextServletContextAwareProcessor(ConfigurableWebApplicationContext webApplicationContext) {
		Assert.notNull(webApplicationContext, "WebApplicationContext must not be null");
		this.webApplicationContext = webApplicationContext;
	}

	@Override
	protected ServletContext getServletContext() {
		ServletContext servletContext = this.webApplicationContext.getServletContext();
		return (servletContext != null) ? servletContext : super.getServletContext();
	}

	@Override
	protected ServletConfig getServletConfig() {
		ServletConfig servletConfig = this.webApplicationContext.getServletConfig();
		return (servletConfig != null) ? servletConfig : super.getServletConfig();
	}

}

3.2.2 <1.2> 处,忽略 ServletContextAware 接口

  • 因为实现 ServletContextAware 接口的 Bean 在 <1.1> 中的 WebApplicationContextServletContextAwareProcessor 中已经处理了。

3.2.3 <2> 处,注册 ExistingWebApplicationScopes 方法

调用 #registerWebApplicationScopes() ,代码如下:

	private void registerWebApplicationScopes() {
	 	// 创建 ExistingWebApplicationScopes 对象
		ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
		// 注册 ExistingWebApplicationScopes 到 WebApplicationContext 中
		WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
		// 恢复
		existingScopes.restore();
	}

3.3 #onRefresh()方法

在容器初始化时,完成 WebServer 的创建(不包括启动),代码如下:

	@Override
	protected void onRefresh() {
		// <1> 调用父方法
		super.onRefresh();
		try {
		// <2>创建 WebServer
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

3.3.1 #createWebServer() 方法

创建 WebServer 对象

	// ServletWebServerApplicationContext.java
	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		// <1> 如果 webServer 为空,说明未初始化
		if (webServer == null && servletContext == null) {
			// <1.1> 获得 ServletWebServerFactory 对象
			ServletWebServerFactory factory = getWebServerFactory();
			// <1.2> 获得 ServletContextInitializer 对象
			// <1.3> 创建(获得) WebServer 对象
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		// <3> 初始化 PropertySource
		initPropertySources();
	}

(1)<1> 处,如果 webServer 为空,说明未初始化。

  • <1.1> 处,调用 #getWebServerFactory() 方法,获得 ServletWebServerFactory 对象。
    • 默认情况下,此处返回的会是 org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory 对象。

    • 在我们引入 spring-boot-starter-web 依赖时,默认会引入 spring-boot-starter-tomcat 依赖。此时,org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration 在自动配置时,会配置出 TomcatServletWebServerFactory Bean 对象。因此,此时会获得 TomcatServletWebServerFactory 对象。

代码如下:

	// ServletWebServerApplicationContext.java
	protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		// 获得 ServletWebServerFactory 类型对应的 Bean 的名字们
		String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
		// 如果是 0 个,抛出 ApplicationContextException 异常,因为至少要一个
		if (beanNames.length == 0) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
					+ "ServletWebServerFactory bean.");
		}
		// 如果是 > 1 个,抛出 ApplicationContextException 异常,因为不知道初始化哪个
		if (beanNames.length > 1) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
					+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
		}
		// 获得 ServletWebServerFactory 类型对应的 Bean 对象
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}
  • <1.2> 处,调用 #getSelfInitializer() 方法,获得 ServletContextInitializer 对象。
    返回的是 ServletContextInitializer 匿名对象,内部会调用 #selfInitialize(servletContext) 方法。该方法会在 WebServer 创建后,进行初始化。

代码如下:

// ServletWebServerApplicationContext.java

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
	return this::selfInitialize; // 和下面等价
//        return new ServletContextInitializer() {
//
//            @Override
//            public void onStartup(ServletContext servletContext) throws ServletException {
//                selfInitialize(servletContext);
//            }
//
//        };
}
  • <1.3> 处,创建(获得) WebServer 对象。
    调用 ServletWebServerFactory#getWebServer(ServletContextInitializer) 方法。

(2)<3> 处,调用父 #initPropertySources() 方法,初始化 PropertySource

3.3.2 #selfInitialize()

初始化 WebServer ,代码如下:

	// ServletWebServerApplicationContext.java
	private void selfInitialize(ServletContext servletContext) throws ServletException {
		// <1> 添加 Spring 容器到 servletContext 属性中。
		prepareWebApplicationContext(servletContext);
		// <2> 注册 ServletContextScope
		registerApplicationScope(servletContext);
		// <3> 注册 web-specific environment beans ("contextParameters", "contextAttributes")
		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
		// <4> 获得所有 ServletContextInitializer ,并逐个进行启动
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
			beans.onStartup(servletContext);
		}
	}

(1)<1> 处,添加 Spring 容器到 servletContext 属性中。
调用 #prepareWebApplicationContext(ServletContext servletContext) 方法,

  • 通过 处,从 servletContext 的属性种,可以拿到其拥有的 Spring 容器。
  • 通过 处,Spring 容器的 servletContext 属性,可以拿到 ServletContext 对象。

代码如下:

	protected void prepareWebApplicationContext(ServletContext servletContext) {
		// 如果已经在 ServletContext 中,则根据情况进行判断。
		Object rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		if (rootContext != null) {
			// 如果是相同容器,抛出 IllegalStateException 异常。说明可能有重复的 ServletContextInitializers 。
			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 {
			// <X> 设置当前 Spring 容器到 ServletContext 中
			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 + "]");
			}
			// <Y> 设置到 `servletContext` 属性中。
			setServletContext(servletContext);
			// 打印日志
			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - getStartupDate();
				logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
			}
		}
		catch (RuntimeException | Error ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
	}

(2)<2> 处,注册 ServletContextScope
调用 #registerApplicationScope(ServletContext servletContext) 方法,代码如下:

	// ServletWebServerApplicationContext.java
	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);
	}

(3)<3> 处,注册 web-specific environment beans。

  • 调用 WebApplicationContextUtils#registerEnvironmentBeans(ConfigurableListableBeanFactory bf, ServletContext sc) 方法
  • 这样,从 BeanFactory 中,也可以获得到 servletContext

代码如下:

public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
        if (servletContext != null && !bf.containsBean("servletContext")) {
            bf.registerSingleton("servletContext", servletContext);
        }

        if (servletConfig != null && !bf.containsBean("servletConfig")) {
            bf.registerSingleton("servletConfig", servletConfig);
        }

        HashMap attributeMap;
        Enumeration attrNameEnum;
        String attrName;
        if (!bf.containsBean("contextParameters")) {
            attributeMap = new HashMap();
            if (servletContext != null) {
                attrNameEnum = servletContext.getInitParameterNames();

                while(attrNameEnum.hasMoreElements()) {
                    attrName = (String)attrNameEnum.nextElement();
                    attributeMap.put(attrName, servletContext.getInitParameter(attrName));
                }
            }

            if (servletConfig != null) {
                attrNameEnum = servletConfig.getInitParameterNames();

                while(attrNameEnum.hasMoreElements()) {
                    attrName = (String)attrNameEnum.nextElement();
                    attributeMap.put(attrName, servletConfig.getInitParameter(attrName));
                }
            }

            bf.registerSingleton("contextParameters", Collections.unmodifiableMap(attributeMap));
        }

        if (!bf.containsBean("contextAttributes")) {
            attributeMap = new HashMap();
            if (servletContext != null) {
                attrNameEnum = servletContext.getAttributeNames();

                while(attrNameEnum.hasMoreElements()) {
                    attrName = (String)attrNameEnum.nextElement();
                    attributeMap.put(attrName, servletContext.getAttribute(attrName));
                }
            }

            bf.registerSingleton("contextAttributes", Collections.unmodifiableMap(attributeMap));
        }

    }

3.4 finishRefresh()

在容器初始化完成时,启动 WebServer 。覆写 #finishRefresh() 方法,代码如下:

// ServletWebServerApplicationContext.java

@Override
protected void finishRefresh() {
    // <1> 调用父方法
    super.finishRefresh();
    // <2> 启动 WebServer
    WebServer webServer = startWebServer();
    // <3> 如果创建 WebServer 成功,发布 ServletWebServerInitializedEvent 事件
    if (webServer != null) {
        publishEvent(new ServletWebServerInitializedEvent(webServer, this));
    }
}

3.4.1 <1> 处,调用 #finishRefresh() 方法,执行父逻辑

	protected void finishRefresh() {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

3.4.2 <2> 处,启动 WebServer

调用 #startWebServer() 方法,代码如下:

// ServletWebServerApplicationContext.java

private WebServer startWebServer() {
	WebServer webServer = this.webServer;
	if (webServer != null) {
		webServer.start();
	}
	return webServer;
}

3.5 onClose() 关闭 WebServer

// ServletWebServerApplicationContext.java

@Override
protected void onClose() {
    // 调用父方法
    super.onClose();
    // 停止 WebServer
    stopAndReleaseWebServer();
}
	private void stopAndReleaseWebServer() {
		WebServer webServer = this.webServer;
		if (webServer != null) {
			try {
				webServer.stop();
				this.webServer = null;
			}
			catch (Exception ex) {
				throw new IllegalStateException(ex);
			}
		}
	}


4.AnnotationConfigServletWebServerApplicationContext

  • 继承 ServletWebServerApplicationContext 类,实现 AnnotationConfigRegistry 接口,进一步提供了两个功能:
    • 从指定的 basePackages 包中,扫描 BeanDefinition 们。
    • 从指定的 annotatedClasses 注解的配置类(Configuration)中,读取 BeanDefinition 们。

4.1 构造方法


	// AnnotationConfigServletWebServerApplicationContext.java

	private final AnnotatedBeanDefinitionReader reader;

	private final ClassPathBeanDefinitionScanner scanner;

	private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();

	private String[] basePackages;

	/**
	 * 需要被 {@link #reader} 读取的注册类们
	 */
	public AnnotationConfigServletWebServerApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	/**
	 * 需要被 {@link #scanner} 扫描的包
	 */
	public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	public AnnotationConfigServletWebServerApplicationContext(Class<?>... annotatedClasses) {
		this();
		// <1> 注册指定的注解的类们
		register(annotatedClasses);
		// 初始化 Spring 容器
		refresh();
	}

	public AnnotationConfigServletWebServerApplicationContext(String... basePackages) {
		this();
		// <2> 扫描指定包
		scan(basePackages);
		// 初始化 Spring 容器
		refresh();
	}

}

4.1.1 <1> 处,注册指定的注解的类们.

  • 如果已经传入 annotatedClasses 参数,则调用 #register(Class<?>… annotatedClasses) 方法,设置到 annotatedClasses 中。
  • 然后,调用 #refresh() 方法,初始化 Spring 容器。

代码如下:

	// AnnotationConfigServletWebServerApplicationContext.java
	@Override
	// 实现自 AnnotationConfigRegistry 接口
	public final void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));
	}

4.1.2 <2> 处扫描指定包

  • 如果已经传入 basePackages 参数,则调用 #scan(String… basePackages) 方法,设置到 annotatedClasses 中。
  • 然后,调用 #refresh() 方法,初始化 Spring 容器。代码如下:
	@Override
	public final void scan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		this.basePackages = basePackages;
	}

4.2 prepareRefresh

  • 在 Spring 容器初始化前,需要清空 scanner 的缓存。
  • 覆写 #prepareRefresh() 方法,代码如下:
// AnnotationConfigServletWebServerApplicationContext.java

@Override // 实现自 AbstractApplicationContext 抽象类
protected void prepareRefresh() {
    // 清空 scanner 的缓存
    this.scanner.clearCache();
    // 调用父类
    super.prepareRefresh();
}

4.3 postProcessBeanFactory

  • 覆写 #postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 方法,执行 BeanDefinition 的读取。代码如下:
// AnnotationConfigServletWebServerApplicationContext.java

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 调用父类
    super.postProcessBeanFactory(beanFactory);
    // 扫描指定的包
    if (this.basePackages != null && this.basePackages.length > 0) {
        this.scanner.scan(this.basePackages);
    }
    // 注册指定的注解的类们定的
    if (!this.annotatedClasses.isEmpty()) {
        this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
    }
}




上一篇跳转—Java源码(二)Spring Application Context                下一篇跳转—Java源码(三)SpringBoot Web容器应用上下文



本篇文章主要参考链接如下:

参考链接-芋道源码


持续更新中…

随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,一起学习、交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/442824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

echarts 雷达图

Echarts 常用各类图表模板配置 注意&#xff1a; 这里主要就是基于各类图表&#xff0c;更多的使用 Echarts 的各类配置项&#xff1b; 以下代码都可以复制到 Echarts 官网&#xff0c;直接预览&#xff1b; 图标模板目录 Echarts 常用各类图表模板配置一、雷达图二、环形图三…

27 个Python数据科学库实战案例 (附代码)

为了大家能够对人工智能常用的 Python 库有一个初步的了解&#xff0c;以选择能够满足自己需求的库进行学习&#xff0c;对目前较为常见的人工智能库进行简要全面的介绍。 1、Numpy NumPy(Numerical Python)是 Python的一个扩展程序库&#xff0c;支持大量的维度数组与矩阵运算…

US News退榜风波后,发布最新美国最佳法学院和医学院排名

从2022年11月开始&#xff0c;美国权威排名机构US News不断陷入风波。耶鲁大学法学院率先宣布退出US News法学院排名&#xff0c;先是法学院&#xff0c;后是医学院&#xff0c;包括哈佛大学大学、斯坦福大学、哥伦比亚大学和加州大学伯克利分校等名校也纷纷宣布退出。 这些老…

【C语言】const关键字的作用

文章目录 一. const修饰变量二. const修饰指针三. const修饰函数参数 一. const修饰变量 被 const 修饰的变量具有常属性&#xff0c;这里的常属性指的是变量的值不能被修改 int main() {// const可以写在类型之前&#xff0c;也可以写在类型之后int const a 10;a 20;// er…

【操作系统——内存的基本知识,逻辑地址到物理地址的转换,操作系统对内存空间的分配和回收以及扩充和保护】

文章目录 内存的基本知识什么是内存&#xff1f;内存有什么作用&#xff1f;进程运行的基本原理知识回顾 内存的管理概念内存空间的扩充内存空间的分配与回收连续分配管理方式动态分区的算法&#xff1a; 内存的基本知识 什么是内存&#xff1f;内存有什么作用&#xff1f; 内…

Linux日志分析

日志的分类 内核以及系统日志 内核及系统日志由系统服务 rsyslog 统一管理&#xff0c;主配置文件为/etc/rsyslog.conf&#xff0c;主程序/sbin/rsyslogd Linux 操作系统本身和大部分服务器程序的日志文件都默认放在目录/var/log/下。 系统日志基于rsyslog服务&#xf…

【LeetCode】剑指 Offer 63. 股票的最大利润 p304 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/gu-piao-de-zui-da-li-run-lcof/ 1. 题目介绍&#xff08;63. 股票的最大利润&#xff09; 假设把某股票的价格按照时间先后顺序存储在数组中&#xff0c;请问买卖该股票一次可能获得的最大利润是多少&#xff1f; 【测试用…

自然语言处理 —— 02 基于规则的词法分析

一、什么是词法分析? 词:是自然语言中能够独立运用的最小单位,是语言信息处理的基本单位。 词法分析:是词汇层的分析技术。主要包括词的识别、形态分析、词性标注等任务。 1. 词的识别 将句子转换成词序列【就是分词?】 2. 形态分析 词的构成、形态变化、词形还原。 …

物联网定位技术|实验报告|实验三 PDM定位算法

目录 1. 实验目标 2. 实验要求 3. 算法介绍 3.1 PDM算法 4. 算法实现 第一步&#xff1a;将数据读入内存 第二步&#xff1a;判断锚节的个数 第三步&#xff1a;将所有的两点间的距离关系读入距离矩阵 第四步&#xff1a;利用最短路径算法 第五步&#xff1a;构造节点跳数矩…

JVM-0419~20

类的加载 类的加载过程&#xff08;生命周期&#xff09; 类的加载分几步&#xff1f; 按照Java虚拟机规范&#xff0c;从class文件到加载到内存中的类&#xff0c;到类卸载出内存为止&#xff0c;它的整个生命周期包括如下7个阶段&#xff1a; 基本数据类型在虚拟机里面都预…

【智能座舱系列】-华为发布全球首款车载光场屏 开拓车载视觉体验新航道

4月16日,2023华为智能汽车解决方案“内赋智能,焕发新生”新品发布会在上海举行,华为正式发布全新车载娱乐屏品类:HUAWEI xScene 光场屏。该产品采用独创的光学引擎技术,具有大画幅、景深感、低晕动、眼放松等特点,大幅提升车内视觉体验。 华为光场屏:私人影院装入车内,…

非常详细的阻抗测试基础知识

编者注&#xff1a;为什么要测量阻抗呢&#xff1f;阻抗能代表什么&#xff1f;阻抗测量的注意事项... ...很多人可能会带着一系列的问题来阅读本文。不管是数字电路工程师还是射频工程师&#xff0c;都在关注各类器件的阻抗&#xff0c;本文非常值得一读。全文13000多字&#…

2. 算法分析

2. 算法分析 研究算法的最终目的就是如何花更少的时间&#xff0c;如何占用更少的内存去完成相同的需求。 我们要计算算法时间耗费情况&#xff0c;首先我们得度量算法的执行时间&#xff0c;那么如何度量呢&#xff1f; 2.1 算法的时间复杂度分析 事后分析估算方法&#x…

关于web安全测试在功能测试中的应用

关于web安全测试在功能测试中的应用 一、安全基本概念1.1实施安全评估1.1.1资产等级划分1.1.2威胁分析1.1.3风险分析1.1.4 安全方案 1.2 安全原则 二、我的安全测试模型三、安全测试在功能测试中的应用3.1 更改url3.2 逻辑缺陷&#xff1a;3.3 破坏流程顺序3.4 接口提示信息3.5…

HNU-计算机系统-讨论课5

WARNING&#xff1a; 本题为开放性题目&#xff0c;所设计的也仅仅是一个可能的模型而已&#xff0c;再考虑到个人水平有限。在呈现效果上难免会有缺漏以及可行性的缺陷。故请批判性地接收&#xff01; 所以如果知识有错误或者缺漏&#xff0c;请一定要指出&#xff0c;您的建…

计算机类大学生竞赛经验分享

如果你是作为一个科班出生的学习编程方向的一名在校大学生&#xff0c;那么如果对竞赛感兴趣&#xff0c;可以看看这篇文章 本人作为一名前端开发方向的学生&#xff0c;将自己这几年的参赛经验和比赛相关类型介绍分享给大家 首先我们要知道&#xff0c;竞赛分为三种大概的方向…

《类和对象》(上篇)

本文主要对类和对象有一个初步的了解。 文章目录 前言1、类的引入和定义2、类的访问限定符及封装2.1 访问限定符2.2 封装 3 、类的作用域4 、类的实例化5 、类对象的模型5.1 类对象的大小5.2 类对象存储方式 6、this 指针6.1 引子6.2 特性6.3 this指针的一个问题 前言 C语言是面…

MySQL插入和查询blob字段类型的sql语句

创建表&#xff1a; CREATE TABLE t_inpatient_medical_records ( id bigint(20) NOT NULL AUTO_INCREMENT, inpatient_record_code varchar(32) DEFAULT NULL COMMENT 就诊流水号, patient_name varchar(256) DEFAULT NULL COMMENT 患者姓名, pat_id varchar(16) DEFAULT NULL…

java数据类型的转换以及精度丢失

java数据类型的转换以及精度丢失_long转double会丢失精度吗_ღLiJia的博客-CSDN博客 一.浮点类型在计算机当中的存储 float存储需求是4字节&#xff08;32位&#xff09;, 其中1位最高位是符号位&#xff0c;中间8位表示阶位&#xff0c;后32位表示值 float的范围: -2^128 ~ …

搞懂哈希散列

文章目录 1. 哈希概念2. 如何解决哈希冲突&#xff1f;3. 哈希函数概念4. 闭散列(目前淘汰的方法&#xff0c;了解&#xff09;**4.1.线性探测****4.2. 二次探测**4.3 闭散列查找与删除 5. 开散列6. 开散列与闭散列比较 1. 哈希概念 搜索树需要多次的关键码比较来搜索到结果&a…