之前在使用spring boot框架搭建一个web服务时,一直想详细研究下spring boot的源码,主要是bean加载到IOC容器和Spring Aop这两个功能的具体实现,最近有时间就在家看了下spring关于这两个功能的源码,也在网上找了些资料去看,发现大部分资料写的都是偏重于某一块源码的讲解,我是希望能够按照spring boot的启动流程来分析这两个功能,这样的话能够前后连贯,理解起来也会更容易,否则单独讲这两部分的话,很多东西不知道在哪完成初始化的,因此关于spring 源码学习的第一篇文章就从spring boot框架的启动开始讲解。
@SpringBootApplication
public class Chapter1Application {
public static void main(String[] args) {
SpringApplication.run(Chapter1Application.class, args);
}
}
通过调用SpringApplication的run方法就可以快速启动一个web应用。这个run方法里最后会调用下面这个run方法。
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这个run方法中new了一个SpringApplication实例,在构造函数中调用了initialize方法,在这个方法里主要做了三件事:
(1)检查当前启动的应用是否是一个web应用。如果是webEnvironment 变量的值为true,检测的方法是能否通过反射实例化下面这两个类来判断。
"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"
(2) 设置ApplicationContextInitializer实现类,这些实现类是配置在META-INF/spring.factories文件中,这些实现类后面会使用。
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
(3) 设置listener监听器,这些监听器也是配置在META-INF/spring.factories下如下:
org.springframework.context.ApplicationListener=
org.springframework.boot.ClearCachesApplicationListener,
org.springframework.boot.builder.ParentContextCloserApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,
org.springframework.boot.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.logging.LoggingApplicationListener
这些监听器是spring启动时,自动加载的。用户也可以自己实现ApplicationListener接口,按照业务的要求实现具体的监听器,对spring的事件监听机制不熟悉的可以参考这篇文章sping监听器。
初始化SpringApplication实例后,调用SpringApplication的run方法,看下这个run方法实现。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
}
这个方法比较长,spring的启动就是在这个方法中完成的,我们还是按照步骤来分析这个方法。
(1)获取SpringApplicationRunListeners对象,获取方式与之前获取ApplicationListener实现类相同,也是从spring.factories中获取具体的SpringApplicationRunListeners实现类。
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener这个类的主要作用是根据spring启动的不同时期,触发不同的事件类型。之前设置的监听器,每个监听器对应不同的事件,事件类型匹配时会触发对应监听器的onApplicationEvent方法,这是一个典型的观察者模式。这个类的具体代码可以参考EventPublishingRunListener。
(2)触发EventPublishingRunListener的starting方法。
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
这个方法就会触发一个ApplicationStartedEvent事件,通知这个事件对应的监听器完成具体的业务。
(3)创建ApplicationContext对象。
这个对象非常重要,Spring IOC的实现主要就是基于这个对象。看下怎么创建的。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
根据是否是一个web应用,确定ApplicationContext的具体类型。本文以web应用为例,初始化一个AnnotationConfigEmbeddedWebApplicationContext类,具体初始化过程参考ApplicationContext对象初始化过程。
(4)执行prepareContext操作。
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
。。。
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
}
这个方法中主要对上一步创建的ApplicationContext做一些初始化操作,调用applyInitializers方法。
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
这个方法中会遍历之前添加的实现ApplicationContextInitializer的初始化子类,然后调用这些子类的initialize方法,完成对ApplicationContext的一些初始化操作。
例如:
ContextIdApplicationContextInitializer类会为ApplicationContext生成一个唯一的id。
DelegatingApplicationContextInitializer类会从application.properties配置文件中读取key为context.initializer.classes的实现ApplicationContextInitializer的初始化子类,这样就允许开发者自己添加ApplicationContextInitializer子类。
遍历完初始化子类后,执行listeners.contextPrepared(context),这个是触发监听器操作的,这个方法目前是空,不会触发监听器的执行。
然后执行load方法,加载Spring boot框架的主函数所在的类到ApplicationContext中,看下加载过程。
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
初始化一个BeanDefinitionLoader类,然后调用load方法,省略中间调用过程,调用下面这个load方法。
private int load(Class<?> source) {
。。。
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
首先加载的类是否含有@Component注解,然后调用annotatedReader.register(source)方法,annotatedReader实例对应的实现类是AnnotatedBeanDefinitionReader类,忽略中间调用过程,最终会调用下面这个register方法。
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
首先创建一个基于注解的AnnotatedGenericBeanDefinition实现类,这个类中保存了bean的所有信息。
然后调用this.scopeMetadataResolver.resolveScopeMetadata(abd)这个方法。
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
这个方法主要是判断类中是否有@Scope注解,如果有这个注解会获取这个注解对应的value和proxyMode属性,关于这个注解可以参考@Scope。获取完@Scope注解属性后返回ScopeMetadata对象。根据返回的ScopeMetadata对象,设置AnnotatedGenericBeanDefinition中这个bean的Scope属性。
调用AnnotationConfigUtils.processCommonDefinitionAnnotations(abd)这个方法完成对这个类中注解的解析,代码如下。
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
if (metadata.isAnnotated(Lazy.class.getName())) {
abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
}
else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
if (metadata.isAnnotated(DependsOn.class.getName())) {
abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
}
if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
if (metadata.isAnnotated(Role.class.getName())) {
absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
}
if (metadata.isAnnotated(Description.class.getName())) {
absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
}
}
}
解析完常用注解后,将这个AnnotatedGenericBeanDefinition放入BeanDefinitionHolder对象中,然后调用AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry)。
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
如果bean中含有@Scope注解,则根据proxyMode属性生成一个代理对象。
生成代理对象后,将这个代理对象放入ApplicationContext中DefaultListableBeanFactory中的beanDefinitionMap这个map中。
到这里prepareContext方法的大部分功能就完成了。
(5)refresh Context
上一步只是初始化了context的一些参数,创建了context里创建bean的DefaultListableBeanFactory,将sping boot启动的主函数类放入beanDefinitionMap这个map中,项目中的其他定义的bean还未被扫描放入beanDefinitionMap,以及beanDefinitionMap中放入的bean还没有被实例化。这些操作其实是在refresh Context这一步完成。
这一步的内容比较多,也比较复杂,我们在bean加载详细讲解。
我们接下来还是继续分析启动的主流程。
(6)最后调用listeners.finished(context, null)
看下fininshed这个方法
public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
}
其实就是发送一个ApplicationReadyEvent事件触发监听此事件的监听器,我看了下之前加载的监听器好像没有监听此事件的监听器,当然用户也可以自己定义关于此事件的监听器。
到这里springboot 启动的大概流程就分析完了,大部分的文章对这部分都是一概而过,直接去讲bean的加载,但是这里还是有很多内容需要清楚的,这样才能更明白类的调用关系、监听器模式、bean是如何加载的。
下一节就具体讲bean加载。