public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
SpringApplication构造器的主流程
最终来到了这个构造器:
1 2 3 4 5 6 7 8 9 10 11 12 13
/** Create a new SpringApplication instance. The application context will load beans from the specified primary sources (see class-level documentation for details. The instance can be customized before calling run(String...). 创建一个应用上下文,应用 上下文会从指定的primarySources加载,这个实例可以在调用run方法之前进行一个定制化。 */ public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader;//为null Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//com.twodragonlake.boot.MyApplication.class this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
Callback interface for initializing a Spring ConfigurableApplicationContext prior to being refreshed. Typically used within web applications that require some programmatic initialization of the application context. For example, registering property sources or activating profiles against the context's environment. See ContextLoader and FrameworkServlet support for declaring a "contextInitializerClasses" context-param and init-param, respectively. ApplicationContextInitializer processors are encouraged to detect whether Spring's Ordered interface has been implemented or if the @Order annotation is present and to sort instances accordingly if so prior to invocation.
在bean刷新之前初始化 Spring ConfigurableApplicationContext的一个回调接口。 通常用于在web应用当中,需要编程的方式初始化应用的上下文。 比如我们注册 一个属性源,激活profile这对于上下文的环境。 ApplicationContextInitializer被鼓励探测spring排序接口是不是被实现或者@Order注解是不是存在,存在的话用来排序。 ApplicationContextInitializer主要用来完成初始化工作。
逻辑很简单,默认返回线程上下文类加载器 public static ClassLoader getDefaultClassLoader() { ClassLoader cl = null; try { cl = Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back... } //如果线程上下文类加载器是空的,就返回ClassUtils的类加载器 if (cl == null) { // No thread context class loader -> use class loader of this class. cl = ClassUtils.class.getClassLoader(); //如果ClassUtils的类加载器也是空的就返回系统类加载器 if (cl == null) { // getClassLoader() returning null indicates the bootstrap ClassLoader try { cl = ClassLoader.getSystemClassLoader(); } catch (Throwable ex) { // Cannot access system ClassLoader - oh well, maybe the caller can live with null... } } } return cl; }
我们的程序返回的是系统类加载器(线程上下文类加载器中的) Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); type是ApplicationContextInitializer.class, 这里SpringFactoriesLoader加载了工厂的名字: SpringFactoriesLoader解析: doc: General purpose factory loading mechanism for internal use within the framework. SpringFactoriesLoader loads and instantiates factories of a given type from “META-INF/spring.factories” files which may be present in multiple JAR files in the classpath. The spring.factories file must be in Properties format, where the key is the fully qualified name of the interface or abstract class, and the value is a comma-separated list of implementation class names. For example: example.MyService=example.MyServiceImpl1,example.MyServiceImpl2 where example.MyService is the name of the interface, and MyServiceImpl1 and MyServiceImpl2 are two implementations. 在框架内部所使用的的一种通用工厂加载机制。 SpringFactoriesLoader从文件 “META-INF/spring.factories” 里边指定的类型工厂进行加载和实例化。 这个文件可能位于classpath下多个jar文件当中。spring.factories文件必须要是Properties格式的,其中key就是接口或者抽象类的完全限定的名字,值是逗号分隔的实现类名字的列表。举例: example.MyService=example.MyServiceImpl1,example.MyServiceImpl2 其中example.MyService是接口的名字,example.MyServiceImpl1,example.MyServiceImpl2是2个实现类。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null");
try { /** ReflectionUtils.makeAccessible实现,即如果不可访问的改为可访问的。 public static void makeAccessible(Constructor<?> ctor) { if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) { ctor.setAccessible(true); } } **/ ReflectionUtils.makeAccessible(ctor); //对java和kotlin类型的进行生成。 return KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? BeanUtils.KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args); } catch (InstantiationException var3) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", var3); } catch (IllegalAccessException var4) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var4); } catch (IllegalArgumentException var5) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var5); } catch (InvocationTargetException var6) { throw new BeanInstantiationException(ctor, "Constructor threw exception", var6.getTargetException()); } }
org.springframework.context @FunctionalInterface public interface ApplicationListener extends EventListener Interface to be implemented by application event listeners. Based on the standard java.util.EventListener interface for the Observer design pattern. As of Spring 3.0, an ApplicationListener can generically declare the event type that it is interested in. When registered with a Spring ApplicationContext, events will be filtered accordingly, with the listener getting invoked for matching event objects only. 一个用来被应用事件监听实现的接口,基于标准的java.util.EventListener接口,是一种观察者模式。 在Spring 3.0版本,一个应用监听器可以声明一个它感兴趣的事件类型,当注册到spring的应用上下文里边,事件将相应的过滤,当注册的事件发生的时候,监听器就会被触发。
1 2 3 4 5 6 7 8 9 10 11
ApplicationListener是一个函数式接口 @FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event);
看一下它的doc Simple stop watch, allowing for timing of a number of tasks, exposing total running time and running time for each named task. Conceals use of System.currentTimeMillis(), improving the readability of application code and reducing the likelihood of calculation errors. Note that this object is not designed to be thread-safe and does not use synchronization. This class is normally used to verify performance during proof-of-concepts and in development, rather than as part of production applications. Since: May 2, 2001
Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this. An ApplicationContext provides:
Bean factory methods for accessing application components. Inherited from ListableBeanFactory.
The ability to load file resources in a generic fashion. Inherited from the org.springframework.core.io.ResourceLoader interface.
The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.
The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.
Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.
In addition to standard org.springframework.beans.factory.BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware, ApplicationEventPublisherAware and MessageSourceAware beans. See Also: ConfigurableApplicationContext, org.springframework.beans.factory.BeanFactory, org.springframework.core.io.ResourceLoader
org.springframework.context public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the ApplicationContext interface. Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.
/** Callback interface used to support custom reporting of SpringApplication startup errors. reporters are loaded via the SpringFactoriesLoader and must declare a public constructor with a single ConfigurableApplicationContext parameter. 用来支持对于SpringApplication启动错误的自定义的报告的回调接口,reporters是通过SpringFactoriesLoader加载的,并且声明一个public的带有ConfigurableApplicationContext类型的参数的构造器。 */ @FunctionalInterface public interface SpringBootExceptionReporter {
/** * Report a startup failure to the user. * @param failure the source failure 失败的源 * @return {@code true} if the failure was reported or {@code false} if default * reporting should occur. 报告一个启动失败, */ boolean reportException(Throwable failure);
}
它有唯一一个实现类FailureAnalyzers,构造器如下:
1 2 3 4 5 6
FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) { Assert.notNull(context, "Context must not be null"); this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader(); this.analyzers = loadFailureAnalyzers(this.classLoader); prepareFailureAnalyzers(this.analyzers, context); }
最后返回的是SpringApplicationRunListeners,SpringApplicationRunListeners里边有一个集合【 private final List listeners;】 因为有必要看那一下 SpringApplicationRunListener的doc
SpringApplicationRunListener类
org.springframework.boot public interface SpringApplicationRunListener Listener for the SpringApplication run method. SpringApplicationRunListeners are loaded via the SpringFactoriesLoader and should declare a public constructor that accepts a SpringApplication instance and a String[] of arguments. A new SpringApplicationRunListener instance will be created for each run.
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } }
SimpleApplicationEventMulticaster
构造器里边初始化了一个SimpleApplicationEventMulticaster,看一下介绍: org.springframework.context.event public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster Simple implementation of the ApplicationEventMulticaster interface. Multicasts all events to all registered listeners, leaving it up to the listeners to ignore events that they are not interested in. Listeners will usually perform corresponding instanceof checks on the passed-in event object. By default, all listeners are invoked in the calling thread. This allows the danger of a rogue listener blocking the entire application, but adds minimal overhead. Specify an alternative task executor to have listeners executed in different threads, for example from a thread pool. ApplicationEventMulticaster接口的简单实现。 广播所有的事件给所有注册的监听器,对于不感兴趣的事件的过滤的决定权留给每个监听器自己去处理。监听器对于传递过来的时间对象通常会进行instanceof检查,默认情况,所有的监听器都会在被调用的线程去执行,这样就会存在一种危险,某一些监听器会阻塞整个的应用,但确是最小的成本,用一个替代的任务执行器拥有这个监听器,这样在不同的线程去执行,比如在线程池里边。
看一下EventPublishingRunListener的starting方法:
1 2 3 4
public void starting() { this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); }
这里冒出来一个ApplicationStartingEvent。
ApplicationStartingEvent
org.springframework.boot.context.event public class ApplicationStartingEvent extends SpringApplicationEvent Event published as early as conceivably possible as soon as a SpringApplication has been started - before the Environment or ApplicationContext is available, but after the ApplicationListeners have been registered. The source of the event is the SpringApplication itself, but beware of using its internal state too much at this early stage since it might be modified later in the lifecycle.
org.springframework.core.env public interface Environment extends PropertyResolver
Interface representing the environment in which the current application is running. Models two key aspects of the application environment: profiles and properties. Methods related to property access are exposed via the PropertyResolver superinterface. A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schema or the @Profile annotation for syntax details. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default. Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them. Beans managed within an ApplicationContext may register to be EnvironmentAware or @Inject the Environment in order to query profile state or resolve properties directly. In most cases, however, application-level beans should not need to interact with the Environment directly but instead may have to have ${…} property values replaced by a property placeholder configurer such as PropertySourcesPlaceholderConfigurer, which itself is EnvironmentAware and as of Spring 3.1 is registered by default when using context:property-placeholder/. Configuration of the environment object must be done through the ConfigurableEnvironment interface, returned from all AbstractApplicationContext subclass getEnvironment() methods. See ConfigurableEnvironment Javadoc for usage examples demonstrating manipulation of property sources prior to application context refresh().
接下来是ConfigurableEnvironment,也就是Environment的子类,看一下doc: org.springframework.core.env public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver
Configuration interface to be implemented by most if not all Environment types. Provides facilities for setting active and default profiles and manipulating underlying property sources. Allows clients to set and validate required properties, customize the conversion service and more through the ConfigurablePropertyResolver superinterface. Manipulating property sources Property sources may be removed, reordered, or replaced; and additional property sources may be added using the MutablePropertySources instance returned from getPropertySources(). The following examples are against the StandardEnvironment implementation of ConfigurableEnvironment, but are generally applicable to any implementation, though particular default property sources may differ. Example: adding a new property source with highest search priority ConfigurableEnvironment environment = new StandardEnvironment(); MutablePropertySources propertySources = environment.getPropertySources(); Map<String, String> myMap = new HashMap<>(); myMap.put(“xyz”, “myValue”); propertySources.addFirst(new MapPropertySource(“MY_MAP”, myMap));
Example: removing the default system properties property source MutablePropertySources propertySources = environment.getPropertySources(); propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
Example: mocking the system environment for testing purposes MutablePropertySources propertySources = environment.getPropertySources(); MockPropertySource mockEnvVars = new MockPropertySource().withProperty(“xyz”, “myValue”); propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars);
When an Environment is being used by an ApplicationContext, it is important that any such PropertySource manipulations be performed before the context’s refresh() method is called. This ensures that all property sources are available during the container bootstrap process, including use by property placeholder configurers. 一个不是被所有也是被大多数Environment类型所实现的配置接口,提供了设置活动的默认的profiles,以及操作底层的属性元的基础设施,允许客户端设置和验证所要求的属性,定制转换服务,都是通过ConfigurablePropertyResolver这样的一个父接口进行的。 如何操纵属性源? 属性源可以被删除,重排序也可以被替换,并且额外的属性来源可以通过MutablePropertySources进行添加,通过getPropertySources方法进行获取,接下来的举例针对于ConfigurableEnvironment的标准环境的实现,不过和特定的默认的属性源有点不同。 例子:添加了一个高搜索优先级的属性源:
1 2 3 4 5
ConfigurableEnvironment environment = new StandardEnvironment(); MutablePropertySources propertySources = environment.getPropertySources(); Map<String, String> myMap = new HashMap<>(); myMap.put("xyz", "myValue"); propertySources.addFirst(new MapPropertySource("MY_MAP", myMap));
// 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(); } } }
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { //启动应用运行器 callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { //启动命令行运行器 callRunner((CommandLineRunner) runner, args); } } }
ApplicationRunner
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple ApplicationRunner beans can be defined within the same application context and can be ordered using the Ordered interface or @Order annotation.
@FunctionalInterface public interface ApplicationRunner {
/** * Callback used to run the bean. * @param args incoming application arguments * @throws Exception on error */ void run(ApplicationArguments args) throws Exception;
}
CommandLineRunner
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined within the same application context and can be ordered using the Ordered interface or @Order annotation. If you need access to ApplicationArguments instead of the raw String array consider using ApplicationRunner.
@FunctionalInterface public interface CommandLineRunner {
/** * Callback used to run the bean. * @param args incoming main method arguments * @throws Exception on error */ void run(String... args) throws Exception;