——————原创文章,如有转载请说明出处
介绍prestoServer启动过程之前,需要先介绍Guice依赖注入初始化框架,因为presto启动过程的初始化用的就是Guice框架。本文分两部分,第一部分介绍Guice框架,第二部分介绍prestoServer的启动过程。
一 Guice框架:
Guice是一个轻量级的IOC控制反转框架。google提供。
没有面向接口编程就没有依赖注入(Dependency Injection),接口用实例传入即是IOC。
所谓的绑定就是将一个接口绑定到具体的类中,这样客户端不用关心具体的实现,而只需要获取相应的接口完成其服务即可。
Guice的优点:
1.速度快,比sping快100倍
2.无外部配置
3.简单,学习溜
4.动态绑定(在Provider节解释)
简单例子1:
public interface Add {
public int add(int a, int b);
}
public class SimpleAdd implements Add {
@Override
public int add(int a, int b) {
return a + b;
}
}
public class AddModule implements Module {
@Override
public void configure(Binder binder) {
binder.bind(Add.class).to(SimpleAdd.class);
}
}
public class AddClient {
/**
* @param one-bird
*/
public static void main(String[] args) {
Injector injector=Guice.createInjector(new AddModule());
Add add=injector.getInstance(Add.class);
System.out.println(add.add(2016, 1119));
}
}
简单例子2:
public class Player {
public String name;
public Player() {
}
public String toString() {
return name;
}
}
public class PlayerTest {
/**
* @param one-bird
*/
public static void main(String[] args) {
Injector injector = Guice.createInjector();
Player player = injector.getInstance(Player.class);
player.name = "live";
System.out.println(player);
}
}
简单例子3:
public class Mobile {
private String number;
public Mobile() {
this.number = "20161114";
}
public String toString() {
return "[Mobile: " + number + "]";
}
}
public class Laptop {
private String model;
private String price;
public Laptop() {
this.model = "HP 20161119";
this.price = "$1119";
}
public String toString() {
return "[Laptop: " + model + "," + price + "]";
}
}
public class Person {
private Mobile mobile;
private Laptop laptop;
@Inject
public Person(Mobile mobile, Laptop laptop) {
this.mobile = mobile;
this.laptop = laptop;
}
public void displayInfo() {
System.out.println("Mobile:" + mobile);
System.out.println("Laptop:" + laptop);
}
}
public class MultipleDependencyTest {
/**
* @param one-bird
*/
public static void main(String[] args) {
Injector injector=Guice.createInjector();
Person person=injector.getInstance(Person.class);
person.displayInfo();
}
}
核心概念:
Module:
Guice提供依赖配置类,继承自AbstractModule,实现configure方法,在configure方法中我们可以用Binder配置依赖。
Bind:
接口绑定实现
下面介绍多种绑定方式:
类绑定
实例绑定
@注解绑定
@Named绑定
@Provides
用于运行是执行
@Provided By
用于动态绑定
Injector:
Injector injector = Guice.createInjector(new XXXModule(bundleContext));
injector.getInstance(xxx.class);
Guice:
门面
Guice.createInjector
Inject:
依赖注入,IOC核心。目前有构造函数注入,方法注入,属性注入三种方式,在3者前面添加@Inject注解即可。
范围:
@Singleton
NO_SCOPE
SINGLETON
二 prestoServer启动过程:
prestoServer 在presto-main 模块下,包名com.facebook.presto.server。
main函数进来后直接run()
public static void main(String[] args)
{
new PrestoServer().run();
}
run()函数如下:
public void run()
{
verifyJvmRequirements();
verifySystemTimeIsReasonable();
Logger log = Logger.get(PrestoServer.class);
ImmutableList.Builder modules = ImmutableList.builder();
modules.add(
new NodeModule(),
new DiscoveryModule(),
new HttpServerModule(),
new JsonModule(),
new JaxrsModule(true),
new MBeanModule(),
new JmxModule(),
new JmxHttpModule(),
new LogJmxModule(),
new TraceTokenModule(),
new JsonEventModule(),
new HttpEventModule(),
new EmbeddedDiscoveryModule(),
new ServerSecurityModule(),
new AccessControlModule(),
new ServerMainModule(sqlParserOptions),
new GracefulShutdownModule(),
installModuleIf(
NodeSchedulerConfig.class,
config -> LEGACY_NETWORK_TOPOLOGY.equalsIgnoreCase(config.getNetworkTopology()),
binder -> binder.bind(NetworkTopology.class).to(LegacyNetworkTopology.class).in(Scopes.SINGLETON)),
installModuleIf(
NodeSchedulerConfig.class,
config -> "flat".equalsIgnoreCase(config.getNetworkTopology()),
binder -> binder.bind(NetworkTopology.class).to(FlatNetworkTopology.class).in(Scopes.SINGLETON))
);
modules.addAll(getAdditionalModules());
Bootstrap app = new Bootstrap(modules.build());
try {
Injector injector = app.strictConfig().initialize();
injector.getInstance(PluginManager.class).loadPlugins();
injector.getInstance(CatalogManager.class).loadCatalogs();
// TODO: remove this huge hack
updateDatasources(
injector.getInstance(Announcer.class),
injector.getInstance(Metadata.class),
injector.getInstance(ServerConfig.class),
injector.getInstance(NodeSchedulerConfig.class));
injector.getInstance(AccessControlManager.class).loadSystemAccessControl();
injector.getInstance(Announcer.class).start();
log.info("======== SERVER STARTED ========");
}
catch (Throwable e) {
log.error(e);
System.exit(1);
}
}
用到了guava集合,填充guice module后,传入BootStrap类。
installModuleIf(
NodeSchedulerConfig.class,
config -> LEGACY_NETWORK_TOPOLOGY.equalsIgnoreCase(config.getNetworkTopology()),
binder -> binder.bind(NetworkTopology.class).to(LegacyNetworkTopology.class).in(Scopes.SINGLETON)),
installModuleIf(
NodeSchedulerConfig.class,
config -> "flat".equalsIgnoreCase(config.getNetworkTopology()),
binder -> binder.bind(NetworkTopology.class).to(FlatNetworkTopology.class).in(Scopes.SINGLETON))
installModuleIf利用java8 lamda的condition:
public static Module installModuleIf(Class config, Predicate predicate, Module module)
{
return new ConditionalModule<>(config, predicate, module);
}
injector本来是通过Guice静态方法得到,目前通过BootStrap的initialize得到。
最后通过Announcer启动:
injector.getInstance(Announcer.class).start();
Announcer应该是airlift下的discovery包的类似定时调度的玩意儿。