BeanFactory创建过程(基于Servlet)
- 1. 概述
- 1.2 那么问题就来了
- 1.2.1 谁负责AnnotationConfigServletWebServerApplicationContext实例呢?
- 1.2.2 ApplicationContextFactory初始化过程又是怎么样的?
- 1.3 总结
- 2. 最后
1. 概述
AnnotationConfigServletWebServerApplicationContext
的类图。
在GenericApplicationContext
类有一个构造函数,直接实例化了DefaultListableBeanFactory
,它就是BeanFactory
。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
}
从上面的类图可以看到AnnotationConfigServletWebServerApplicationContext
间接的继承了GenericApplicationContext
,因为类的继承规则,所以只要创建AnnotationConfigServletWebServerApplicationContext
对象,GenericApplicationContext
也会被实例化,自然的DefaultListableBeanFactory
也会被实例化。
1.2 那么问题就来了
1.2.1 谁负责AnnotationConfigServletWebServerApplicationContext实例呢?
有一个ApplicationContextFactory
工厂类,从上图可以发现它有3个实现类,我们主要看基于注解的实现类AnnotationConfigServletWebServerApplicationContext
。可以从下面的实现代码发现,create调用了AnnotationConfigReactiveWebServerApplicationContext无参的构造函数。这个时候问题又来了,ApplicationContextFactory
又是怎么初始化的?
static class Factory implements ApplicationContextFactory {
@Override
public Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.REACTIVE) ? null : ApplicationReactiveWebEnvironment.class;
}
@Override
public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.REACTIVE) ? null : new ApplicationReactiveWebEnvironment();
}
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.REACTIVE) ? null
: new AnnotationConfigReactiveWebServerApplicationContext();
}
}
1.2.2 ApplicationContextFactory初始化过程又是怎么样的?
在spring-boot-2.7.16
的jar包中可以发现spring.factories中有下面两行代码,可以使用SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class, getClass().getClassLoader())
去获取到下面两个对象。
# Application Context Factories
org.springframework.boot.ApplicationContextFactory=\
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory,\
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory
现在清楚是什么情况了,那就把整个创建的过程走一下。
- SpringApplication#run(String…args)
下面创建的BeanFactory
其实就是ConfigurableApplicationContext
,其实在ApplicationContextFactory
中创建的是AnnotationConfigServletWebServerApplicationContext
,从概述的类图中可以看到AnnotationConfigServletWebServerApplicationContext
间接的继承了ConfigurableApplicationContext
。
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 这里就是创建BeanFactory的方法
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
- SpringApplication#createApplicationContext()
- DefaultApplicationContextFactory#create() & getFromSpringFactories()
SpringApplication#createApplicationContext()
方法最终调用了DefaultApplicationContextFactory
类的create方法,又调用getFromSpringFactories方法,这个方法就是从spring.factory
文件找ApplicationContextFactory
的实现类。
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
AnnotationConfigApplicationContext::new);
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
}
// 从spring.factory中获取ApplicationContextFactory的实现类
private <T> T getFromSpringFactories(WebApplicationType webApplicationType,
BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
getClass().getClassLoader())) {
// Java8 的写法这里的action就是ApplicationContextFactory的create方法
// 可以理解为ApplicationContextFactory::create
// 也可以理解为ApplicationContextFactory.create()
T result = action.apply(candidate, webApplicationType);
if (result != null) {
return result;
}
}
return (defaultResult != null) ? defaultResult.get() : null;
}
1.3 总结
这里来一个小总结,方便记忆。下面是整个过程:
SpringApplication#run -> SpringApplication#createAppliction -> DefaultApplicationContextFactory#create -> DefaultApplicationContextFactory#getFromSpringFactory -> SpringFactoriesLoader#loadFactories
可以知道实例化BeanFactory
也就是AnnotationConfigServletWebServerApplicationContext
是DefaultApplicationContextFactory
的实现类去做的,而实例化DefaultApplicationContextFactory
是抛给了spring.factory
。
2. 最后
本篇幅多次提到DefaultListableBeanFactory
,下一章就研究研究BeanFactory
。还有,解读源码发现很多地方都使用到了工厂设计模式,作者修为浅薄,还不能说出所以然,这也是一个值得思考的问题,等我有了新的想法,会在本篇文章上继续分享。