聪百科 手机版
当前位置: 首页 常识

spring工作原理及流程(源码分析Spring启动过程)

时间:2024-09-22 09:00:33


深入了解Spring前,先弄清楚几个问题:

1. Spring是什么?

2. 使用Spring能给我们带来什么?

3. Spring的工作原理是什么?

Spring是一个全栈框架,提供了从表示层到业务层再到持久层的一套完整的解决方案。可以很方便地让应用集成第三方框架组件,快速集成第三方提供的功能。Spring属于低侵入式设计,可以降低各组件之间的耦合性,实现软件各层之间的解耦,加快应用的开发。

Spring 框架的7个模块

spring框架图

组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

· 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

· Spring Context:Spring Context是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

· Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

· Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

· Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

· Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

· Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

Spring 的两大核心IOC和AOP。

以下介绍spring 启动过程是基于springboot方式。

@SpringBootApplication(scanBasePackages = {"com.demo"})
@MapperScan(value = "com.demo")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication .class, args);
}
}

其入口就是SpringApplication.run(DemoApplication.class,args);

/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

// 初始化一些环境变量
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);

// 打印Spring boot的LOGO
Banner printedBanner = printBanner(environment);

// 创建ApplicationContext上下文。
context = createApplicationContext();
exceptionReporters =
getSpringFactoriesInstances(
SpringBootExceptionReporter.class,

new Class[] {
ConfigurableApplicationContext.class }, context);

prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

创建Spring 上下文:Context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
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);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

其中webApplicationType由SpringApplication初始化时指定

this.webApplicationType = WebApplicationType.deduceFromClasspath();

static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

从deduceFromClasspath方法可以看到,如果存在
org.springframework.web.reactive.DispatcherHandler且不存在
org.springframework.web.servlet.DispatcherServlet且不存在
org.glassfish.jersey.servlet.ServletContianer时,WebApplicationType为REACTIVE,否则返回Servlet。此处采用的是默认配置,返回的是Servlet.

所以createApplicationContext初始化的为
web.servlet.context.AnnotationConfigServletWebServerApplicationContext。

创建webApplicationContext后,刷新context前需完成一些准备工作prepareContext()方法。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {

// 设置容器环境
context.setEnvironment(environment);

// 执行容器后置处理

postProcessApplicationContext(context);

// 执行容器中applicationInitializer,包括spring.factories和通过三种方式自定义的initializer
applyInitializers(context);

// 向监听器发送容器已准备好的事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans

ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();


beanFactory.registerSingleton("
springApplicationArguments", applicationArguments);

if (printedBanner != null) {

beanFactory.registerSingleton("springBootBanner", printedBanner);

}
if (beanFactory instanceof
DefaultListableBeanFactory) {

((
DefaultListableBeanFactory) beanFactory)


.setAllowBeanDefinitionOverriding(
this.allowBeanDefinitionOverriding);

}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");

// 加载并注册BeanDefinition
load(context, sources.toArray(new Object[0]));

// 发布容器已加载事件
listeners.contextLoaded(context);
}

Load(context,sources.toArray(new Object[0])方法根据注解,XML或componentScan路径加载bean并注册到BeanDefinitionMap中

刷新ApplicationContext前数据准备好了,接下来执行refreshContext(context)方法。

refreshContext(context)里调用refresh(context)方法

protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}

((
AbstractApplicationContext) applicationContext).refresh();这一句话实际走的就是
AbstractApplicationContext.refresh();

代码来到这里,就与传统的配置spring启动流程一样了。

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 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();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
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.
destroyBeans();
// Reset 'active' flag.
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(),看似个获取一个BeanFactory,其实这方法里做了很多事情,如:加载Bean并注册到spring容器。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}


AbstractRefreshableApplicationContext.refreshBeanFactory()方法:

protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}


DefaultListableBeanFactory 是Spring整个bean加载的核心部分。

loadBeanDefinitions(beanFactory)方法,从方法名可以看出主要功能是解析配置文件中的bean定义并加载注册。

loadBeanDefinitions(beanFactory)解析XML的会走到
AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory)。

最终会调用
XmlBeanDefinitionReader.loadBeanDefinitions(EncodeResource encodeResource);

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

最后通过Document解析XML,并将XML定义的BEAN解析成BeanDefinition。最后通过
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());将BeanDefinition注册到BeanFactory中。

至些解析XML的obtainFreshBeanFactor()方法完成。

代码继续回到
AbstractApplicationContext.refresh()方法中prepareBeanFactory(beanFactory);主要是对新实例化好的BeanFactory对象进行相关的参数设置。


invokeBeanFactoryPostProcessors(beanFactory)方法主要是判断BeanFactory中是否有指定类型的Bean,有则调用其相应的方法。


initApplicationEventMulticaster();方法主要是初始化一个applicationContext事件广播器。

onRefresh();模板方法,执行子类里的onRefresh方法。

registerListeners(); 主要是注册一些应用的监听器。

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


finishBeanFactoryInitialization(beanFactory);主要是实例化剩下所有的非懒加载的单例bean实体。

// Last step: publish corresponding event.

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);
}

最后一步主要是清理一些缓存,触发context完成事件。

至此spring的启动基本完成。

总结:Spring的启动过程就是资源的加载和将注解BEAN或配置文件XML定义的BEAN转换成BeanDefinition并注册到BeanFactory,完成ApplicationContenct上下文创建的过程。

Spring的两大核心基础:BeanFactory,ApplicationContext