本章节继续分析run方法的第15行代码:
public ConfigurableApplicationContext run(String... args) {
1.StopWatch stopWatch = new StopWatch();
2.stopWatch.start();
3.ConfigurableApplicationContext context = null;
4.Collection exceptionReporters = new ArrayList<>();
5.configureHeadlessProperty();
6.SpringApplicationRunListeners listeners = getRunListeners(args);
7.listeners.starting();
try {
8. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
9. ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
10. configureIgnoreBeanInfo(environment);
11. Banner printedBanner = printBanner(environment);
12. context = createApplicationContext();
13. exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
14. prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
15. refreshContext(context);
16. afterRefresh(context, applicationArguments);
17. stopWatch.stop();
18. if (this.logStartupInfo) {
19. new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
20. listeners.started(context);
21. callRunners(context, applicationArguments);
}
catch (Throwable ex) {
22. handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
23. listeners.running(context);
}
catch (Throwable ex) {
24. handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
- 其中第15行的代码如下:
@Override
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();
}
}
}
本章节主要分析:registerBeanPostProcessors,initMessageSource,initApplicationEventMulticaster,onRefresh,registerListeners,finishBeanFactoryInitialization,finishRefresh,destroyBeans,cancelRefresh,resetCommonCaches
registerBeanPostProcessors
- 具体代码如下:registerBeanPostProcessors 本行代码就是注册BeanPostProcessors
具体代码如下:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List priorityOrderedPostProcessors = new ArrayList<>();
List internalPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
先加个BeanPostProcessorChecker,会在beanPostBean创建bean的时候 打印信息或者打印不合格的bean
- 所以通过以上可知道 beanDeifion在BeanFactoryPostProcessor确定
- beanPostProcessor确定最终的bean(因为bean在初始化结束前后可以获取修改bean)
- 查找 四种类型的beanPostProcessor 1.PriorityOrdered 2 Ordered 3 rest 4 internalPostProcessors
其中internalPostProcessors 属于PriorityOrdered 和Ordered 同时是MergedBeanDefinitionPostProcessor 主要是修改RootBeanDefinition - RootBeanDefinition 它可能来源于多个原始Bean定义(继承自其他的bean定义,通常被注册为GenericBeanDefinitions)。RootBeanDefinition从本质上将是运行时统一的Bean定义视图。
在配置阶段,RootBeanDefinition也可能用于注册独立的bean定义。然而,自从Spring2.5依赖,编程地注册bean定义建议使用 GenericBeanDefinition类。GenericBeanDefinition在允许动态定义父依赖而不是硬编码作为RootBeanDefinition方面有优势。 - 然后依次注册 PriorityOrdered Ordered 注册其他的
- 最终在添加一个ApplicationListenerDetector,其主要是检测哪些bean是ApplicationListener
initMessageSource
这个是处理国际化的,具体代码如下:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
- 首先检测是否存在messageSource的bean,若是存在获取这个bean 然后 若是存在父容器,就设置该父容器的messageSource为当前容器的父messageSource,如果父容器不存在messageSource,就设置父容器本身。设置父messageSource的意义是当messageSource无法解析就交给父messageSource
- 若是不存在 设一个emtpymessageSource(DelegatingMessageSource ),继续按照上述逻辑设置父MessageSource ,然后注册该bean
initApplicationEventMulticaster 初始化容器的组播组件
- beanFactory.containsLocalBean(beanName) 只会在当前容器中查找对应的beanName是否存在
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
- 上述方法主要是查看当前beanName是否存在对应的ApplicationEventMulticaster ,存在就注册该bean 不存在就设置SimpleApplicationEventMulticaster为组播组件
onRefresh的代码如下:
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
public static ThemeSource initThemeSource(ApplicationContext context) {
if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
// Make ThemeSource aware of parent ThemeSource.
if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
if (hts.getParentThemeSource() == null) {
// Only set parent context as parent ThemeSource if no parent ThemeSource
// registered already.
hts.setParentThemeSource((ThemeSource) context.getParent());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using ThemeSource [" + themeSource + "]");
}
return themeSource;
}
else {
// Use default ThemeSource to be able to accept getTheme calls, either
// delegating to parent context's default or to local ResourceBundleThemeSource.
HierarchicalThemeSource themeSource = null;
if (context.getParent() instanceof ThemeSource) {
themeSource = new DelegatingThemeSource();
themeSource.setParentThemeSource((ThemeSource) context.getParent());
}
else {
themeSource = new ResourceBundleThemeSource();
}
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
"': using default [" + themeSource + "]");
}
return themeSource;
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
String[] beanNames = getBeanFactory()
.getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start ServletWebServerApplicationContext due to missing "
+ "ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start ServletWebServerApplicationContext due to multiple "
+ "ServletWebServerFactory beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
File documentRoot = getValidDocumentRoot();
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
if (documentRoot != null) {
context.setResources(new LoaderHidingResourceRoot(context));
}
context.setName(getContextPath());
context.setDisplayName(getDisplayName());
context.setPath(getContextPath());
File docBase = (documentRoot != null ? documentRoot
: createTempDir("tomcat-docbase"));
context.setDocBase(docBase.getAbsolutePath());
context.addLifecycleListener(new FixContextListener());
context.setParentClassLoader(
this.resourceLoader != null ? this.resourceLoader.getClassLoader()
: ClassUtils.getDefaultClassLoader());
resetDefaultLocaleMapping(context);
addLocaleMappings(context);
context.setUseRelativeRedirects(false);
configureTldSkipPatterns(context);
WebappLoader loader = new WebappLoader(context.getParentClassLoader());
loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
loader.setDelegate(true);
context.setLoader(loader);
if (isRegisterDefaultServlet()) {
addDefaultServlet(context);
}
if (shouldRegisterJspServlet()) {
addJspServlet(context);
addJasperInitializer(context);
}
context.addLifecycleListener(new StaticResourceConfigurer(context));
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
host.addChild(context);
configureContext(context, initializersToUse);
postProcessContext(context);
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
private void initialize() throws WebServerException {
TomcatWebServer.logger
.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource())
&& Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
removeServiceConnectors();
}
});
// Start the server to trigger initialization listeners
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(),
getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread();
}
catch (Exception ex) {
stopSilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
- 上述代码主要是初始化ThemeSource,如果没有就设置ResourceBundleThemeSource,整个逻辑类似于messageSource
- 创建WebServer
- 如果webServer和servletcontext都为null 则去获取ServletWebServerFactory的bean
- ServletContextInitializer 存在的作用主要是让ServletContextInitializer 可以被spring容器管理 而不被servlet容器管理,且与WebApplicationInitializer不同的是 实现ServletContextInitializer 的实现类且未实现WebApplicationInitializer 不会被SpringServletContainerInitializer检测到,因此不会有servlet容器自动引导。其onStartup方法 主要是配置ServletContext,比如any servlets, filters, listeners context-params and attributes
- WebApplicationInitializer 可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用
SpringServletContainerInitializer作为ServletContainerInitializer的实现类,通过SPI机制,在web容器加载的时候会自动的被调用。(这个类上还有一个注解@HandlesTypes,它的作用是将感兴趣的一些类注入到ServletContainerInitializerde), 而这个类的方法又会扫描找到WebApplicationInitializer的实现类,调用它的onStartup方法,从而起到启动web.xml相同的作用。
- getWebServer 主要是设置设置和启动内置tomcat 设置Connector (默认Nio协议)customizeConnector调整Connector
- prepareContext 就是设置host host内部持有的是spring的TomcatEmbeddedContext
- 最后获取TomcatWebServer并初始化,即设置LifecycleListener并且启动tomcat
registerListeners
- 主要是注册ApplicationListener-当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册等等。这个时候我们就可以使用Spring提供的ApplicationListener来进行操作。
- 然后发布earlyApplicationEvents
finishBeanFactoryInitialization
- 设置beanFactory 的conversion service(其实作为JavaBeans PropertyEditors.的替代者 用来转换属性值)
- 为嵌入值(例如注释属性)添加String解析器。
- 尽早初始化LoadTimeWeaverAware bean以允许尽早注册其变换器。
- 将temporary ClassLoader設置為null
- 冻结所有的beanDefinition,不允许更改
- 实例所有非懒加载的bean对象
finishRefresh
- 清除上下文级资源缓存(例如来自扫描的ASM元数据)。
- 初始化容器的lifecycle processor 比如smartLifeCycle
- 按照phase的大小依次启动lifecycle processor
- 发送ContextRefreshedEvent时间
- 如果LiveBeansView MBean 激活了,则参与LiveBeansView MBean。
destroyBeans 摧毁所有的单例
cancelRefresh 设active标识为false
resetCommonCaches
- 清除反射的缓存
- 清除注解的相关缓存
- Clear the internal {@code ResolvableType}/{@code SerializableTypeWrapper} cache.
- 清除classloader缓存
内置tomcat的说明
内置tomcat的悬疑
首先创建ServletWebServerFactory的bean
然后调用其getWebServer生成WebServer
然后在创建baseDir,根据协议创建Connector和ProtocolHandler(协议处理器)
这个ProtocolHandler主要是设置adapter和Endpoint,而 adapter可以调用connector
adapter提供了service,prepare,asyncDispatch,log,checkRecycled,getDomain
其中domain是用来注册跟这个connector关联的Mbeans
然后创建service,connector,container(enigne),添加valve
下面关键的就来了 我们知道container的顺序是engine,host,context,wrapper
我们这边创建了一个TomcatEmbeddedContext,将spring容器塞入TomcatEmbeddedContext
同时创建一个WebappLoader给当前的TomcatEmbeddedContext
创建一个Wrapper塞入TomcatEmbeddedContext
通过把我们spring容器包装成ServletContextInitializer
然后配置我们的context 包括设置starter(其就是我们ServletContextInitializer的集合类)
设置Valve,ErrorPage,MimeMappings
然后我们启动tomcat(启动server)
最终我们调用ServletWebServerApplicationContext的selfInitialize,其主要是把spring容器
和servletContext 互相绑定,当我们请求时候tomcat最终会调用dispatchServlet,然后把spring容器设置
为该servlet的属性,这样就可以在该servlet使用spring提供的功能
ProtocolHandler 内部包含一个endpoint 也就是说该协议采用
endpoint 进行底层的socket的通信
可以把Endpoint理解 为netty的serverbootStrap
当endpoint发现需要处理的socket,会创建一个SocketProcessor
最终会调用ProtocolHandler的process方法,该方法会创建一个Processor
该Processor会包含adapter,其他的请求信息等
最终adapter会交给对应的container
--
Valve和ContainerBackgroundProcessor
一般只会给engine启动一个线程去执行ContainerBackgroundProcessor
而该任务会执行当前container和其子类容器的 backgroundProcess();
而 一般container的backgroundProcess不仅仅包含container本身还包含该
container的pipeline的valve的backgroundProcess
一般接受一个请求的流程是
Endpoint.Acceptor的acceptor线程接受到请求
一层层处理交给Adapter
而Adapter主要就是调用其service方法把
org.apache.coyote.Request req, org.apache.coyote.Response res
转换为HttpServletRequest和HttpServletResponse
然后交给engine的第一个valve处理
每个容器都有一个pipeline 里面存储链表valve
其最后一个valve都是负责连接下一个container