情况
本文基于Spring Boot版本1.3.3, 利用了spring-boot-starter-web。
设置完成后,软件开发,编写了代码如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
public class RootController {
public static final String PATH_ROOT = "/";
@RequestMapping(PATH_ROOT)
public String welcome() {
return "Welcome!";
}
}
固然只有几行代码,可是这已经是一个完整的Web措施,当会见url的path部门为”/”时,返回字符串”Welcome!”。
首先是一个很是普通的java措施进口,一个切合约定的静态main要领。在这个main要领中,挪用了SpringApplication的静态run要领,并将Application类工具和main要领的参数args作为参数通报了进去。
然后是一个利用了两个Spring注解的RootController类,我们在main要领中,没有直接利用这个类。
SpringApplication类的静态run要领
以下代码摘自:org.springframework.boot.SpringApplication
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
在这个静态要领中,建设SpringApplication工具,并挪用该工具的run要领。
结构SpringApplication工具
以下代码摘自:org.springframework.boot.SpringApplication
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
// 为成员变量sources赋值
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
结构函数中挪用initialize要领,初始化SpringApplication工具的成员变量sources,webEnvironment,initializers,listeners,mainApplicationClass。sources的赋值较量简朴,就是我们传给SpringApplication.run要领的参数。剩下的几个,我们依次来看看是怎么做的。
首先是webEnvironment:
以下代码摘自:org.springframework.boot.SpringApplication
private boolean webEnvironment;
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private void initialize(Object[] sources) {
...
// 为成员变量webEnvironment赋值
this.webEnvironment = deduceWebEnvironment();
...
}
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
可以看到webEnvironment是一个boolean,该成员变量用来暗示当前应用措施是不是一个Web应用措施。那么怎么抉择当前应用措施是否Web应用措施呢,是通过在classpath中查察是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包括的类,假如存在那么当前措施等于一个Web应用措施,反之则否则。
在本文的例子中webEnvironment的值为true。
然后是initializers:
initializers成员变量,是一个ApplicationContextInitializer范例工具的荟萃。 顾名思义,ApplicationContextInitializer是一个可以用来初始化ApplicationContext的接口。
以下代码摘自:org.springframework.boot.SpringApplication
private List<ApplicationContextInitializer<?>> initializers;
private void initialize(Object[] sources) {
...
// 为成员变量initializers赋值
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
...
}
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
可以看到,要害是挪用getSpringFactoriesInstances(ApplicationContextInitializer.class),来获取ApplicationContextInitializer范例工具的列表。
以下代码摘自:org.springframework.boot.SpringApplication
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();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}