SpringBoot 启动过程

启动类

public class BootAppUseEnableSprintBootApplication {

    public static void main (String[] args) {

        SpringApplication app =
            new SpringApplication(BootAppUseEnableSprintBootApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.setLogStartupInfo(false);
        ConfigurableApplicationContext c = app.run(args);
        List<String> packages = AutoConfigurationPackages.get(c);
        System.out.println("packages: "+packages);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

构造SpringApplication对象

	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}
...
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = deduceWebApplicationType();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • this.webEnvironment = deduceWebEnvironment();

对于SpringBoot来说,WebApplicationType有三种

public enum WebApplicationType {

	/**
	 * The application should not run as a web application and should not start an
	 * embedded web server.
	 */
	NONE,

	/**
	 * The application should run as a servlet-based web application and should start an
	 * embedded servlet web server.
	 */
	SERVLET,

	/**
	 * The application should run as a reactive web application and should start an
	 * embedded reactive web server.
	 */
	REACTIVE

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

deduceWebEnvironment方法,根据类路径中是否存在相应的类,来决定WebAppicationType,可以看出如果有REACTIVE_WEB_ENVIRONMENT_CLASS 并且没有MVC_WEB_ENVIRONMENT_CLASS,那么就是REACTIVE类型,如果WEB_ENVIRONMENT_CLASSES中的都没有,那么就是NONE,除此以外情况就是SERVLET

private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.reactive.DispatcherHandler";

private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.servlet.DispatcherServlet";

···
private WebApplicationType deduceWebApplicationType() {
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))设定应用程序初始化器的实例。

initializers 本质是个ArrayList,关键在于getSpringFactoriesInstances(ApplicationContextInitializer.class)

getSpringFactoriesInstances会在SpringAppication.class所在的包内寻找ApplicationContextInitializer的实现。

getSpringFactoriesInstances调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,然后调用createSpringFactoriesInstances方法根据读取到的名字创建对象。最后会将创建好的对象列表排序并返回

SpringFactoriesLoader.loadFactoryNames从spring.factories的资源文件中,读取key为org.springframework.context.ApplicationContextInitializer的value。

ApplicationContextInitializer可能存在于不同jar文件的spring.factories中。例如spring-boot-autoconfigure.jar,spring-boot.jar

createSpringFactoriesInstances来创建ApplicationContextInitializer实例。

  • setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))设置侦听器实例,与setInitializers原理类似
	public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<>();
		this.initializers.addAll(initializers);
	}

...
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

初始化器和侦听器都设定完毕,SpringApplication对象就初始化完毕了。

setBannerMode

设定启动是否显示Banner

	public void setBannerMode(Banner.Mode bannerMode) {
		this.bannerMode = bannerMode;
	}
...

enum Mode {

		/**
		 * Disable printing of the banner.
		 */
		OFF,

		/**
		 * Print the banner to System.out.
		 */
		CONSOLE,

		/**
		 * Print the banner to the log file.
		 */
		LOG

	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

setLogStartupInfo

是否启用启动日志

	public void setLogStartupInfo(boolean logStartupInfo) {
		this.logStartupInfo = logStartupInfo;
	}
1
2
3

最终run

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(
				SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  • StopWatch是来自org.springframework.util的工具类,可以用来方便的记录程序的运行时间。
  • headless模式:实际上是就是设置系统属性java.awt.headless,在我们的例子中该属性会被设置为true,因为我们开发的是服务器程序,一般运行在没有显示器和键盘的环境。关于java中的headless模式,更多信息可以参考http://www.oracle.com/technetwork/articles/javase/headless-136834.html。
  • SpringApplicationRunListeners

run方法中,加载了一系列SpringApplicationRunListener对象,在创建和更新ApplicationContext方法前后分别调用了listeners对象的started方法和finished方法, 并在创建和刷新ApplicationContext时,将listeners作为参数传递到了createAndRefreshContext方法中,以便在创建和刷新ApplicationContext的不同阶段,调用listeners的相应方法以执行操作。所以,所谓的SpringApplicationRunListeners实际上就是在SpringApplication对象的run方法执行的不同阶段,去执行一些操作,并且这些操作是可配置的。

同时,可以看到,加载SpringApplicationRunListener时,使用的是跟加载ApplicationContextInitializer和ApplicationListener时一样的方法。那么加载了什么,就可以从spring.factories文件中看到了.

  • 创建并刷新ApplicationContext
  • 首先是创建一个DefaultApplicationArguments对象
  • 创建并配置ApplicationConext的Environment:Spring Application的Environment代表着程序运行的环境,主要包含了两种信息,一种是profiles,用来描述哪些bean definitions是可用的;一种是properties,用来描述系统的配置,其来源可能是配置文件、JVM属性文件、操作系统环境变量等等。
  • 显示Banner
  • 创建Spring上下文 context = createApplicationContext();
  • 创建异常报告器
  • Spring上下文前置处理
  • Spring上下文刷新
  • Spring上下文后置处理:就是在容器完成刷新后,依次调用注册的Runners。Runners可以是两个接口的实现类: org.springframework.boot.ApplicationRunner,org.springframework.boot.CommandLineRunner

4 SpringApplicationRunListeners

在SpringApplication的run()方法执行时,应用上下文ApplicationContext对象创建之前,应用程序会首先找到配置中所定义的所有SpringApplicationRunListener的实现类(这些实现类可能由Spring boot自身实现和提供,也可以由开发人员来实现和提供),创建他们的实例,然后把它们放在一个集合中,然后封装为一个 SpringApplicationRunListeners 实例。之后Spring boot应用开始创建ApplicationContext对象,然后在相应的ApplicationContext的生命周期事件发生时,程序会通过该SpringApplicationRunListeners 实例向各个 SpringApplicationRunListener 实例广播相应的事件,从而SpringApplicationRunListener 实现类中相应的监听器逻辑得到执行。

发生顺序 事件 简介
1 environmentPrepared 环境已经准备好,但是ApplicationContext实例尚未被创建
2 contextPrepared ApplicationContext已经被创建并且准备就绪,但是sources尚未被加载
3 contextLoaded ApplicationContext实例的sources已经被加载,但是ApplicationContext实例尚未被刷新(refresh)
4 finished Spring应用程序启动完成时发送该事件,此时ApplicationContext实例已经成功创建完成,或者遇到异常创建失败。对于该ApplicationContext是一个WebApplicationContext的情况,此时内置的Web容器已经在其他线程启动处于服务就绪状态,而SpringApplication执行主线程已经完成自己的任务。
class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log,
			Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

	public void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	public void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	public void finished(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFinishedListener(listener, context, exception);
		}
	}

	private void callFinishedListener(SpringApplicationRunListener listener,
			ConfigurableApplicationContext context, Throwable exception) {
		try {
			listener.finished(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message == null ? "no error message" : message);
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

}

public interface SpringApplicationRunListener {

	/**
	 * Called immediately when the run method has first started. Can be used for very
	 * early initialization.
	 */
	void starting();

	/**
	 * Called once the environment has been prepared, but before the
	 * {@link ApplicationContext} has been created.
	 * @param environment the environment
	 */
	void environmentPrepared(ConfigurableEnvironment environment);

	/**
	 * Called once the {@link ApplicationContext} has been created and prepared, but
	 * before sources have been loaded.
	 * @param context the application context
	 */
	void contextPrepared(ConfigurableApplicationContext context);

	/**
	 * Called once the application context has been loaded but before it has been
	 * refreshed.
	 * @param context the application context
	 */
	void contextLoaded(ConfigurableApplicationContext context);

	/**
	 * Called immediately before the run method finishes.
	 * @param context the application context or null if a failure occurred before the
	 * context was created
	 * @param exception any run exception or null if run completed successfully.
	 */
	void finished(ConfigurableApplicationContext context, Throwable exception);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

run-1

SpringApplication.run()调用。


	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified source using default settings.
	 * @param primarySource the primary source to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
	
1
2
3
4
5
6
7
8
9
10
11
12
13

run-2

new SpringApplication

	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
1
2
3
4

run-3

构造

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param primarySources the primary bean sources
	 * @see #run(Class, String[])
	 * @see #SpringApplication(ResourceLoader, Class...)
	 * @see #setSources(Set)
	 */
	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param resourceLoader the resource loader to use
	 * @param primarySources the primary bean sources
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(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;
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    1. Put source in the source attribute of Spring Application, and source is aLinkedHashSet()This means that we can create multiple custom non-repetitive applications at the same time, but there is only one at present.
    1. Determine whether it is a web program (?javax.servlet.Servletandorg.springframework.web.context.ConfigurableWebApplicationContextAll must exist in the class loader and be set towebEnvironmentAttribute.
    1. Find the Application Context Initializer from spring. factories and set it to initializers.
    1. Find the Application Listener from spring. factories and instantiate it into the listener listeners property of Spring Application. This process is to find all the application event listeners.
    1. Find out the main method class and return the Class object.

By default, the initialize method finds the classes whose keys are ApplicationContextInitializer from the spring. factories file:

  • org.springframework.boot.context.config.DelegatingApplicationContextInitializer
  • org.springframework.boot.context.ContextIdApplicationContextInitializer
  • org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
  • org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
  • org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
  • org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer

The key is ApplicationListener.

  • org.springframework.boot.context.config.ConfigFileApplicationListener
  • org.springframework.boot.context.config.AnsiOutputApplicationListener
  • org.springframework.boot.logging.LoggingApplicationListener
  • org.springframework.boot.logging.ClasspathLoggingApplicationListener
  • org.springframework.boot.autoconfigure.BackgroundPreinitializer
  • org.springframework.boot.context.config.DelegatingApplicationListener
  • org.springframework.boot.builder.ParentContextCloserApplicationListener
  • org.springframework.boot.context.FileEncodingApplicationListener
  • org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
  • org.springframework.boot.autoconfigure.BackgroundPreinitializer

SpringFactoriesLoader:

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

run-4


public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		//通过META-INF/spring.factories获取SpringApplicationRunListener类型的实例
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// Called immediately when the run method has first started
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			// 判断创建web容器还是普通IOC容器
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//准备上下文
			//遍历回调ApplicationContextInitializer的initialize事件
			//遍历回调SpringApplicationRunListeners中的contextPrepared事件
			//环境准备完成之后,遍历回调SpringApplicationRunListeners中的contextLoaded事件
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			//刷新上下文,初始化所有自动配置类
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			//The context has been refreshed and the application has started but CommandLineRunners} and ApplicationRunners} have not been called.
			listeners.started(context);
			//ApplicationRunner and CommandLineRunners
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

prepareContext method to associate listeners, environment, application Arguments, banner and other important components with context objects.

prepareContext-》load-》createBeanDefinitionLoader-》BeanDefinitionLoader-》(XmlBeanDefinitionReader,annotatedReader,groovyReader,从xml配置中获得定义)

run-6

ublic void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

refreshContext-》refresh-》invokeBeanFactoryPostProcessors 初始化bean

understanding of spring.handlers and spring.schemas

What is the purpose of spring.handlers and spring.schemas?

some spring libraries contain a spring.schemas and a spring.handlers file inside a META-INF directory

META-INF/spring.schemas

re-maps(*) schemalocation to a xsd inside the library (abstract) only re-mapped versions are supported by this library META-INF/spring.handlers

provides namespace handler classes for specific namespaces the namespace handler class provides the parser logic to parse spring-batch beans, like job, step, etc. (*) the actual re-mapping happens during the build of the spring application context

Common Name Handler

Every Spring namespace has an associated NamespaceHandler implementation. The namespace schemas are mapped to schema files inside Spring JARs in various spring.schemas files (see also Spring DI applicationContext.xml how exactly is xsi:schemaLocation used?).

The XML schema namespaces are also mapped to handler classes in spring.handlers files (several as each Spring JAR might introduce different namespaces). For your convenience here is a list of most common namespaces:

Spring core

  • aop - AopNamespaceHandler
  • c - SimpleConstructorNamespaceHandler
  • cache - CacheNamespaceHandler
  • context - ContextNamespaceHandler
  • jdbc - JdbcNamespaceHandler
  • jee - JeeNamespaceHandler
  • jms - JmsNamespaceHandler
  • lang - LangNamespaceHandler
  • mvc - MvcNamespaceHandler
  • oxm - OxmNamespaceHandler
  • p - SimplePropertyNamespaceHandler
  • task - TaskNamespaceHandler
  • tx - TxNamespaceHandler
  • util - UtilNamespaceHandler

Spring Security

  • security - SecurityNamespaceHandler oauth - OAuthSecurityNamespaceHandler

Spring integration

  • int - IntegrationNamespaceHandler
  • amqp - AmqpNamespaceHandler
  • event - EventNamespaceHandler
  • feed - FeedNamespaceHandler
  • file - FileNamespaceHandler
  • ftp - FtpNamespaceHandler
  • gemfire - GemfireIntegrationNamespaceHandler
  • groovy - GroovyNamespaceHandler
  • http - HttpNamespaceHandler
  • ip - IpNamespaceHandler
  • jdbc - JdbcNamespaceHandler
  • jms - JmsNamespaceHandler
  • jmx - JmxNamespaceHandler
  • mail - MailNamespaceHandler
  • redis - RedisNamespaceHandler
  • rmi - RmiNamespaceHandler
  • script - ScriptNamespaceHandler
  • security - IntegrationSecurityNamespaceHandler
  • sftp - SftpNamespaceHandler
  • stream - StreamNamespaceHandler
  • twitter - TwitterNamespaceHandler
  • ws - WsNamespaceHandler
  • xml - IntegrationXmlNamespaceHandler
  • xmpp - XmppNamespaceHandler