spring boot一般是指定容器启动main方法,然后以命令行方式启动Jar包,如下图:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }这里核心关注2个东西:
1.@SpringBootApplication注解
2.SpringApplication.run()静态方法
下面我们就分别探究这两块内容。
源码如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {核心注解:
@SpringBootConfiguration(实际就是个@Configuration):表示这是一个JavaConfig配置类,可以在这个类中自定义bean,依赖关系等。-》这个是spring-boot特有的注解,常用到。 @EnableAutoConfiguration:详细见这篇博客 @ComponentScan:spring的自动扫描注解,可定义扫描范围,加载到IOC容器。-》这个不多说,spring的注解大家肯定眼熟SpringApplication.run
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args);//1.获取监听器 listeners.starting();-->启动! try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners,//2.准备好环境,触发ApplicationEnvironmentPreparedEvent事件 applicationArguments); Banner printedBanner = printBanner(environment);//打印启动提示字符,默认spring的字符图 context = createApplicationContext();//实例化一个可配置应用上下文 analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments,//3.准备上下文 printedBanner); refreshContext(context);//4.刷新上下文 afterRefresh(context, applicationArguments);//5.刷新上下文后 listeners.finished(context, null);--关闭! stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }实际是SpringApplicationRunListener类
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 使用Set确保的字符串的唯一性 Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1.载入工厂名称集合 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,// 2.创建工厂实例 classLoader, args, names); AnnotationAwareOrderComparator.sort(instances);// 排序 return instances; }当前类的类加载器从META-INF/spring.factories文件中获取SpringApplicationRunListener类的配置
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }上图,获取到工厂类名后,下面来看看META-INF/spring.factories中定义了啥:
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners 这里呢,看这里!!!! org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Application Context Initializers 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 # Application Listeners 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 # Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter哇,都是些类全名称,且key都是接口,value都是实现类。我们根据key=“org.springframework.boot.SpringApplicationRunListener”查询得到实现类value="org.springframework.boot.context.event.EventPublishingRunListener"事件发布启动监听器,一猜也知道肯定要用”反射”根据类名获取类实例,下面很快得到验证...
根据第一步得到的Set<String> names(SpringApplicationRunListener的唯一实现类EventPublishingRunListener)生成"事件发布启动监听器"工厂实例
@SuppressWarnings("unchecked") private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<T>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader);// 利用反射获取类 Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes);// 得到构造器 T instance = (T) BeanUtils.instantiateClass(constructor, args);// 根据构造器和参数构造实例 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }最终执行的是AbstractApplicationContext抽象类的refresh方法。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。 prepareRefresh(); //启动子类的refreshBeanFactory方法.解析xml ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //为BeanFactory配置容器特性,例如类加载器、事件处理器等. prepareBeanFactory(beanFactory); try { //设置BeanFactory的后置处理. 空方法,留给子类拓展用。 postProcessBeanFactory(beanFactory); //调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的. invokeBeanFactoryPostProcessors(beanFactory); //注册Bean的后处理器, 在Bean创建过程中调用. registerBeanPostProcessors(beanFactory); //初始化上下文中的消息源,即不同语言的消息体进行国际化处理 initMessageSource(); //初始化ApplicationEventMulticaster bean,应用事件广播器 initApplicationEventMulticaster(); //初始化其它特殊的Bean, 空方法,留给子类拓展用。 onRefresh(); //检查并向容器注册监听器Bean registerListeners(); //实例化所有剩余的(non-lazy-init) 单例Bean. finishBeanFactoryInitialization(beanFactory); //发布容器事件, 结束refresh过程. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } //销毁已经创建的单例Bean, 以避免资源占用. destroyBeans(); //取消refresh操作, 重置active标志. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { //重置Spring的核心缓存 resetCommonCaches(); } } }spring boot提供的2个供用户自己拓展的接口:ApplicationRunner和CommandLineRunner。可以在容器启动完毕后(上下文刷新后)执行,做一些类似数据初始化的操作。
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<Object>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//从上下文中获取ApplicationRunner类型的bean runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//从上下文中获取CommandLineRunner类型的bean AnnotationAwareOrderComparator.sort(runners);//排序 for (Object runner : new LinkedHashSet<Object>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args);//执行 } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } } 两个区别在于入参不同,根据实际情况自己选择。 public interface CommandLineRunner { void run(String... args) throws Exception; } public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }CommandLineRunner中执行参数是原始的java启动类main方法的String[] args字符串数组参数;ApplicationRunner中的参数经过处理提供一些方法例如:
List<String> getOptionValues(String name);
根据名称获取值list,java 启动命令中 --foo=bar --foo=baz,则根据foo参数名返回list["bar", "baz"]
二、总结
原文地址