1 |
|
这是一个非常普通的java程序入口,一个符合约定的静态main方法。在这个main方法中,调用了SpringApplication的静态run方法,并将Application类对象和main方法的参数args作为参数传递了进去
SpirngApplication的静态run方法
1 | public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) { |
构造SpringApplication对象
1 | public SpringApplication(Class<?>... primarySources) { |
判断WebApplicationType
1 | private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" }; |
通过ClassUtils.isPresent(url,null)
来判断项目中是否包含对应的类,此处就是判断是否存在Web应用程序对应的包类,反之则不然
设置成员变量initializers
1 | private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { |
initializers成员变量,是一个ApplicationContextInitializer类型对象的集合。 顾名思义,ApplicationContextInitializer是一个可以用来初始化ApplicationContext的接口,通过getSpringFactoriesInstances方法
加载出实例
getClassLoader
通过ClassUtils.getDefaultClassLoader()
获取默认类加载器
SpringFactoriesLoader.loadFactoryNames
1 | //通过读取 META-INF/spring.factories 下的配置,可以获取到相应类需要加载的实现类 |
createSpringFactoriesInstances
1 | private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,Set<String> names) { |
AnnotationAwareOrderComparator.sort
1 | public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator(); |
AnnotationAwareOrderComparator
是一个比较器,用来比较两个实例的order顺序,实例会实现接口Ordered
,可以设置实例的顺序。通过Arrays.sort(数组, 比较器)
来进行归并算法的排序
1 | public interface Ordered { |
设置成员变量listeners
listeners成员变量,是一个ApplicationListener<?>类型对象的集合。可以看到获取该成员变量内容使用的是跟成员变量initializers一样的方法
,同样是通过getSpringFactoriesInstances方法
加载出实例,只不过传入的类型从ApplicationContextInitializer.class变成了ApplicationListener.class
deduceMainApplicationClass:通过方法堆栈推断
通过new RuntimeException().getStackTrace()
获取运行时的执行方法堆栈信息,以此来推断出运行主类main
1 | private Class<?> deduceMainApplicationClass() { |
StackTrace
用栈的形式保存了方法的调用信息,可以通过Thread.currentThread().getStackTrace()
方法来获取堆栈
SpringApplication对象的run方法
1 | public ConfigurableApplicationContext run(String... args) { |
SpringApplicationRunListeners
1 | private SpringApplicationRunListeners getRunListeners(String[] args) { |
SpringApplicationRunListeners中的listeners
同样是通过getSpringFactoriesInstances方法
加载出实例,传入的接口类型是SpringApplicationRunListener.class
,并循环开启监听
1 | public void starting() { |
prepareEnvironment:构建环境
1 | private ConfigurableEnvironment prepareEnvironment( |
getOrCreateEnvironment
根据应用类型获取环境
1 | private ConfigurableEnvironment getOrCreateEnvironment() { |
1 | public abstract class AbstractEnvironment implements ConfigurableEnvironment { |
configureEnvironment
1 | protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) { |
configurePropertySources首先查看SpringApplication对象的成员变量defaultProperties,如果该变量非null且内容非空,则将其加入到Environment的PropertySource列表的最后。然后查看SpringApplication对象的成员变量addCommandLineProperties和main函数的参数args,如果设置了addCommandLineProperties=true,且args个数大于0,那么就构造一个由main函数的参数组成的PropertySource放到Environment的PropertySource列表的最前面(这就能保证,我们通过main函数的参数来做的配置是最优先的,可以覆盖其他配置)
listeners.environmentPrepared
1 |
|
ConfigurationPropertySources.attach
将sources封装成了一个名叫configurationProperties的ConfigurationPropertySourcesPropertySource对象,并把这个对象放到了sources的第一个位置。SpringConfigurationPropertySources是一个将MutablePropertySources转换成ConfigurationPropertySources的适配器
createApplicationContext:创建上下文
根据应用类型创建ApplicationContext对象
1 | protected ConfigurableApplicationContext createApplicationContext() { |
prepareContext:准备上下文
1 | private void prepareContext(ConfigurableApplicationContext context, |
applyInitializers
1 | protected void applyInitializers(ConfigurableApplicationContext context) { |
各个初始化实现类的作用:
load sources:加载source到应用上下文
BeanDefinitionLoader用于从源加载Bean的定义信息,并封装成BeanDefinition对象,并注册到ApplicationContext中,加载的源可以是类注解、XML文件、package、classpath、Groovy文件(多种不同的启动方式)
1 | protected void load(ApplicationContext context, Object[] sources) { |
refreshContext:刷新上下文
1 | private void refreshContext(ConfigurableApplicationContext context) { |
1 | public void refresh() throws BeansException, IllegalStateException { |
prepareRefresh:准备刷新上下文
1 | protected void prepareRefresh() { |
obtainFreshBeanFactory:让子类去创建一个全新的BeanFactory
1 | protected final void refreshBeanFactory() throws BeansException { |
invokeBeanFactoryPostProcessors【重点】:实例化并调用所有已注册的工厂后置处理对象
1 | protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { |
- BeanDefinition
BeanDefinition描述了一个bean实例,它具有属性值,构造函数参数值以及具体实现提供的更多信息
- BeanDefinitionRegistry
BeanDefinitionRegistry用于注册BeanDefinition
注意
其中有一个PostProcessor就是解析配置了注解的Bean:ConfigurationClassPostProcessor
,并执行ConfigurationClassParser.doProcessConfigurationClass()
方法,最终调用ComponentScanAnnotationParser.parse()
,会扫描所有包下的注入的bean的BeanDefinition,并将其设置到spring的上下文中
1 | public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { |
registerListeners:注册事件监听器
1 | protected void registerListeners() { |
finishBeanFactoryInitialization:初始化其他的单例Bean(非延迟加载的)
1 | protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { |
beanFactory.preInstantiateSingletons()
会根据上下文中扫描到的BeanDefinition
,来创建单例实例,并放到spring上下文中
1 | public class DefaultListableBeanFactory{ |
finishRefresh:完成刷新过程,并做一些通知
1 | protected void finishRefresh() { |
注意
此处可以编写整个项目启动后要做的事情
1 |
|
工具类
LogFactory:日志工厂
1 | LogFactory.getLog(FinishRefreshListener.class).info("测试日志:完成"); |
StringUtils:字符串工具类
StringUtils.toStringArray():Collection转数组
1 | public static String[] toStringArray(Collection<String> collection) { |
StringUtils.arrayToCommaDelimitedString(sources):数组转‘,’分隔的字符串
1 | public static String arrayToCommaDelimitedString(@Nullable Object[] arr) { |
BeanUtils:Bean工具类
BeanUtils.instantiateClass():根据类名创建实例
1 | public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException { |
CollectionUtils:Collection工具类
CollectionUtils.isEmpty(xx):判断是否为空
1 | public static boolean isEmpty(@Nullable Collection<?> collection) { |
Assert.isInstanceOf:判断 提供对象是提供类的实例
1 | Assert.isInstanceOf(requiredType, context, "Unable to call initializer"); |
ResolvableType.forClass():获取接口的具体信息(包含信息泛型等)
1 | ResolvableType resolvableType = ResolvableType.forClass(clazz).as(genericIfc); |
AnnotationUtils:注解工具类
AnnotationUtils.findAnnotation():判断是否包含注解Component
1 | if (AnnotationUtils.findAnnotation(type, Component.class) != null) { |
ObjectUtils:对象工具类
ObjectUtils.isEmpty(this.basePackages):判断对象是否为空