随着数据量的不断增大,大数据时代的到来,互联网技术的不断发展和变革,微服务架构和云服务平台以及大数据成为了时下最热门的话题。现在,比较流行的微服务框架也有很多, 比如阿里的Dubbo,基于soringBoot的SpringCloud,Apache的thrift,google的Grpc,这些都提供了很多高并发以及负载均衡等的一系列的解决方案。而我们今天的主角,就是热度最高的SpringCloud,目前只支持java。
springCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。 而SpringCloud之所以又这么完善的解决方案和体系,得益于他兼容了很多优秀的开源的框架,这个之后会具体的一个个温习。今天,我们就先从SpringCloud的启动开始看,学习一下他的启动和加载过程。
相比大家对于SpringBoot或者SpringCloud都不陌生,他的启动方式很简单:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
当然,也可以分开写,像下面这样:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(EurekaClientApplication.class);
application.run(args);
}
}
其实二者的本质是完全一样的。@SpringBootApplication注解就是备注这个服务为SpringBoot服务,关于注解这里就先不详细讲了,之后会单独花时间去详细说明,结合反射一起。今天,先重点弄清楚启动流程以及都做了什么。我们就按照第二种模式,分两个方法进行探索。
首先看第一行代码,SpringApplication application = new SpringApplication(EurekaClientApplication.class);这个是一个简单的构造方法,大概能够猜测是实例化一个SpringApplication。接下来上代码:
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = this.deduceWebApplicationType();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
重点来了,这里主要做了三件事。
Set names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
这两行代码就是具体实现,他会加载所有spring包下的META-INF/spring.factories,里面会有类实现接口的描述,这样,通过接口,可以找到所有的实现类,进而初始化这些类的实例对象。
上面有具体的路径,大家可以点进去看一下,具体的接口和实现类的描述和排版,类似于一个键值对的关系。
这里,就是我们之前启动SpringCloud的第二行代码,调用SpringApplicaiton的run方法。这里代码模块较复杂,建议debug模式下一步步细看,首先,我们贴出源码:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, new Object[]{context});
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}