此篇文章继续解析SpringApplication的run
方法具体代码如下:
public ConfigurableApplicationContext run(String... args) {
1.StopWatch stopWatch = new StopWatch();
2.stopWatch.start();
3.ConfigurableApplicationContext context = null;
4.Collection<SpringBootExceptionReporter> 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;
}
一共24行代码,本章主要解析15小节,其就是真正的把spring容器初始化的方法,基本上把spring容器的大部分功能都包含在内
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
最终注册方法就是这个doClose
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
卸载当前的spring容器,包含卸载该spring容器相关的MBeanServer
LiveBeansView.unregisterApplicationContext(this);
try {
发布关闭事件
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
停止所有实现SmartLifecycle或者Lifecycle的bean,lifecycleProcessor 就是
负责这些bean的声明周期
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
摧毁容器中的所有单例bean
destroyBeans();
关闭bean工厂
closeBeanFactory();
关闭我们内置的tomcat的容器
onClose();
设置未激活标识
this.active.set(false);
}
refresh(context);
的详细代码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
清除ClassPathBeanDefinitionScanner的缓存
设置servletContext和servletConfig,如果这个两个属性不为空则替换
environment的source中关于这个两个的属性
校验必须存在的properties是否存在(我们可以设置哪些properties)
设置earlyApplicationEvents,存储早期的ApplicationEvents,当所有的ApplicationContextListener都注册进入容器之后在执行这些事件
prepareRefresh();
获取beanFactory,还给其设置了refreshed标识
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
准备beanFactory,在注册bean之前先给beanFactory注册一堆bean,这些bean可以
帮助beanFactory后期去解析,注册其他的bean,比如忽略依赖,比如指定依赖
ignoreDependencyInterface:当我们spring指定自动注入的时候会忽略对这个指定参数的EnvironmentAware的注入
registerResolvableDependency:当我们spring指定自动注入的时候会只注入我们指定的参数属性
prepareBeanFactory(beanFactory);
try {
设置ignoreDependencyInterface(ServletContextAware.class),标识对于ServletContextAware
的实现类中的ServletContextAware属性禁止自动注入
如果存在basePackages和annotatedClasses,则扫描basePackages,并把扫描到的class和annotatedClasses注册到spring容器中
postProcessBeanFactory(beanFactory);
执行beanFactory的PostProcessors
按照这个顺序PriorityOrdered,Ordered,nonOrdered
分别执行BeanDefinitionRegistry的postProcessBeanDefinitionRegistry,
BeanFactoryPostProcessor的postProcessBeanFactory
alreadyCreated:这个集合存储已经初始化好的bean实例,
所以当我们执行完beanFactoryPostProcessor的方法时候 会清除未初始化的bean
也会清除allBeanNamesByType和singletonBeanNamesByType
invokeBeanFactoryPostProcessors(beanFactory);
注册beanPostProcessor(会确保spring的internalPostProcessors)一定是排在beanPostProcessor的集合最后
registerBeanPostProcessors(beanFactory);
给spring的容器和其父容器设置messageSource
initMessageSource();
给spring的容器注册一个事件广播器applicationEventMulticaster
initApplicationEventMulticaster();
初始化tomcat
onRefresh();
注册所有的ApplicationListener,并且执行之前积攒的earlyApplicationEvents
registerListeners();
初始化所有非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
清理resource的缓存,初始化LifecycleProcessor用来执行
lifeCycle的bean的onRefresh,
发布ContextRefreshedEvent,将该spring容器注册到
LiveBeansView,启动tomcat发布tomcat启动事件
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();
}
}
}
每行代码的意思都有英文解释,我们一行行来分析
prepareRefresh();
的详细代码如下:
protected void prepareRefresh() {
this.scanner.clearCache();
super.prepareRefresh();
}
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
第一步主要是父类AbstractApplicationContext的refresh方法(因为其子类AnnotationConfigServletWebServerApplicationContext 没有实现该方法)
refresh:
- 该方法第一步调用子类的 prepareRefresh()方法
- 子类的prepareRefresh方法清除CachingMetadataReaderFactory中的缓存然后继续调用父类的prepareRefresh方法
prepareRefresh: - 设置相关属性 校验environment的properties是否正确
- initPropertySources会调用GenericWebApplicationContext的实现 就是设置容器的环境初始化容器的属性
- earlyApplicationEvents 是在multicaster 可用的时候进行发布
obtainFreshBeanFactory()
的代码如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
- 首先ConfigurableListableBeanFactory 是在初始化容器的时候其父类容器也被初始化了才赋值的
spring容器是通过ConfigurableListableBeanFactory 这个bean工厂进行真正的bean加载
- 然后就是首先查看beanFactory是否已经refresh过,如果是 就给容器一个id 同时返回容器
prepareBeanFactory(beanFactory);
的详细代码如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
- 上述代码的作用如下:
- 设置beanFactory的classloader,一般都是线程上下文类加载器
- 设置beanFactory的BeanExpressionResolver,用来根据bean的表达式来解析bean
- 增加ResourceEditorRegistrar,主要是注册用户或者系统定义的属性编辑器
- 添加BeanPostProcessor-ApplicationContextAwareProcessor
1.BeanPostProcessor 提供了2个方法
postProcessBeforeInitialization(该方法在调用bean的初始化方法(注意是初始化方法此时bean早已经实例化好了))
postProcessAfterInitialization(该方法是在调用bean的初始化方法后进行调用)
还需注意的是@service @component 都没有初始化方法 但是@Bean注解有
还有需要注意的是若是上述2中方法对bean 进行修改那么原始的bean就会被替换
而ApplicationContextAwareProcessor则是只修改postProcessBeforeInitialization,
方法内部就是判断 bean是否属于
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
不同的aware调用不同的方法
代码细节如下:
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
而ignoreDependencyInterface 则是正好对应着上述的
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
--ignoreDependencyInterface的真正意思是在自动装配时忽略指定接口的实现类中,对外的依赖。
如果想忽略指定类的自动注入使用ignoreDependencyType
- autowiring特定指的是通过beans标签default-autowire 即@Bean注解
,发现英语中的autowiring特定指的是通过beans标签default-autowire属性来依赖注入的方式,而不是指使用@Autowired注解进行的依赖注入。区别在于,使用default-autowire会自动给所有的类都会从容器中查找匹配的依赖并注入,而使用@Autowired注解只会给这些注解的对象从容器查找依赖并注入。
- 所谓的自动装配是指我们配置ben的xml 或者@Bean的时候 会自动帮我们注入属性(比如我们配置A类的B属性=3),那么容器就会给我们生成一个属性为3的A的实例对象
如果上述几个Aware不使用ignoreDependencyInterface会有什么问题尼,很简单 如果我们写一个实现类,然后给他默认配置ApplicationContext属性,而这个ApplicationContext是我们自己new的,这就导致了我们使用的不是spring自己生成的ApplicationContext,所以spring为了避免我们手误自己注册下这个属性,而帮我们忽略。
而registerResolvableDependency意思更简单了
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
上述代码的意思就是当我们使用自动注入比如@AutoWired注入BeanFactory 类型的那么他会帮我们注入我们目前输入的实例对象,而不会去注入他的其他实现类,这是为了避免我们使用其他的自定义的实例对象
ApplicationListenerDetector
是检测ApplicationListener的实现类是否是单例
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
上述检测是否存在代码织入,简介如下抄袭别人博客的定义:
在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入。编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中;而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;运行期织入则是采用CGLib工具或JDK动态代理进行切面的织入。
AspectJ采用编译期织入和类加载期织入的方式织入切面,是语言级的AOP实现,提供了完备的AOP支持。它用AspectJ语言定义切面,在编译期或类加载期将切面织入到Java类中。
AspectJ提供了两种切面织入方式,第一种通过特殊编译器,在编译期,将AspectJ语言编写的切面类织入到Java类中,可以通过一个Ant或Maven任务来完成这个操作;第二种方式是类加载期织入,也简称为LTW(Load Time Weaving)
如何使用Load Time Weaving?首先,需要通过JVM的-javaagent参数设置LTW的织入器类包,以代理JVM默认的类加载器;第二,LTW织入器需要一个 aop.xml文件,在该文件中指定切面类和需要进行切面织入的目标类。
本人对上述LTW似懂非懂
下面的代码就没什么好讲的了,就是检测某个属性是否存在,然后注册单例bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
refresh中的postProcessBeanFactory 等以下代码留着明天分享