環境準備
源碼下載
國內:https://gitee.com/mirrors/vertx
github: https://github.com/eclipse-vertx/vert.x
解決依賴報錯
本系列以3.8爲基礎進行分析,所以請講源碼調整到3.8分支,
並修改pom.xml:
<stack.version>3.8.0</stack.version>
由於maven倉庫的3.8.0不存在後邊的SNAPSHOT,如果不修改則maven找不到相應的配置文件
啓動流程
初始化vertx
@Override
public Vertx vertx() {
return vertx(new VertxOptions());
}
@Override
public Vertx vertx(VertxOptions options) {
if (options.getEventBusOptions().isClustered()) {
throw new IllegalArgumentException("Please use Vertx.clusteredVertx() to create a clustered Vert.x instance");
}
return VertxImpl.vertx(options);
}
VertxOptions配置請查看另外一篇博客
static VertxImpl vertx(VertxOptions options) {
VertxImpl vertx = new VertxImpl(options, Transport.transport(options.getPreferNativeTransport()));
vertx.init();
return vertx;
}
//transport 與netty的相同,具體請自行學習netty相關知識
private VertxImpl(VertxOptions options, Transport transport) {
// Sanity check
if (Vertx.currentContext() != null) {
log.warn("You're already on a Vert.x context, are you sure you want to create a new Vertx instance?");
}
//關閉vertx時觸發的handler
closeHooks = new CloseHooks(log);
//阻塞線程檢查(檢查Map<VertxThread, Object> threads中註冊的線程,線程通過registerThread來註冊)
checker = new BlockedThreadChecker(options.getBlockedThreadCheckInterval(), options.getBlockedThreadCheckIntervalUnit(), options.getWarningExceptionTime(), options.getWarningExceptionTimeUnit());
//通過VertxThreadFactory創建EventLoop線程池
eventLoopThreadFactory = new VertxThreadFactory("vert.x-eventloop-thread-", checker, false, options.getMaxEventLoopExecuteTime(), options.getMaxEventLoopExecuteTimeUnit());
//根據eventLoopThreadFactory的配置真正的創建eventLoopGroup
eventLoopGroup = transport.eventLoopGroup(options.getEventLoopPoolSize(), eventLoopThreadFactory, NETTY_IO_RATIO);
// //創建Acceptor線程池 類似與多reactor模型中的mainReactor,即netty中的bossGroup
ThreadFactory acceptorEventLoopThreadFactory = new VertxThreadFactory("vert.x-acceptor-thread-", checker, false, options.getMaxEventLoopExecuteTime(), options.getMaxEventLoopExecuteTimeUnit());
// The acceptor event loop thread needs to be from a different pool otherwise can get lags in accepted connections
// under a lot of load
acceptorEventLoopGroup = transport.eventLoopGroup(1, acceptorEventLoopThreadFactory, 100);
metrics = initialiseMetrics(options);
//Vertx會初始化兩個線程池workerExec和internalBlockingExec
ExecutorService workerExec = Executors.newFixedThreadPool(options.getWorkerPoolSize(),
new VertxThreadFactory("vert.x-worker-thread-", checker, true, options.getMaxWorkerExecuteTime(), options.getMaxWorkerExecuteTimeUnit()));
//線程池的metrics
PoolMetrics workerPoolMetrics = metrics != null ? metrics.createPoolMetrics("worker", "vert.x-worker-thread", options.getWorkerPoolSize()) : null;
ExecutorService internalBlockingExec = Executors.newFixedThreadPool(options.getInternalBlockingPoolSize(),
new VertxThreadFactory("vert.x-internal-blocking-", checker, true, options.getMaxWorkerExecuteTime(), options.getMaxWorkerExecuteTimeUnit()));
PoolMetrics internalBlockingPoolMetrics = metrics != null ? metrics.createPoolMetrics("worker", "vert.x-internal-blocking", options.getInternalBlockingPoolSize()) : null;
internalBlockingPool = new WorkerPool(internalBlockingExec, internalBlockingPoolMetrics);
namedWorkerPools = new HashMap<>();
workerPool = new WorkerPool(workerExec, workerPoolMetrics);
defaultWorkerPoolSize = options.getWorkerPoolSize();
defaultWorkerMaxExecTime = options.getMaxWorkerExecuteTime();
defaultWorkerMaxExecTimeUnit = options.getMaxWorkerExecuteTimeUnit();
this.transport = transport;
this.fileResolver = new FileResolver(options.getFileSystemOptions());
this.addressResolverOptions = options.getAddressResolverOptions();
this.addressResolver = new AddressResolver(this, options.getAddressResolverOptions());
this.deploymentManager = new DeploymentManager(this);
if (options.getEventBusOptions().isClustered()) {
this.clusterManager = getClusterManager(options);
this.eventBus = new ClusteredEventBus(this, options, clusterManager);
} else {
this.clusterManager = null;
this.eventBus = new EventBusImpl(this);
}
this.sharedData = new SharedDataImpl(this, clusterManager);
}
VertxThreadFactory的構建方法:
VertxThreadFactory(String prefix, BlockedThreadChecker checker, boolean worker, long maxExecTime, TimeUnit maxExecTimeUnit) {
this.prefix = prefix;
this.checker = checker;
this.worker = worker;
this.maxExecTime = maxExecTime;
this.maxExecTimeUnit = maxExecTimeUnit;
}
public Thread newThread(Runnable runnable) {
VertxThread t = new VertxThread(runnable, prefix + threadCount.getAndIncrement(), worker, maxExecTime, maxExecTimeUnit);
// Vert.x threads are NOT daemons - we want them to prevent JVM exit so embededd user doesn't
// have to explicitly prevent JVM from exiting.
if (checker != null) {
checker.registerThread(t);
}
addToMap(t);
// I know the default is false anyway, but just to be explicit- Vert.x threads are NOT daemons
// we want to prevent the JVM from exiting until Vert.x instances are closed
t.setDaemon(false);
return t;
}
transport.eventLoopGroup:
public EventLoopGroup eventLoopGroup(int nThreads, ThreadFactory threadFactory, int ioRatio) {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(nThreads, threadFactory);
eventLoopGroup.setIoRatio(ioRatio);
return eventLoopGroup;
}
deployVerticle
@Override
public void deployVerticle(Supplier<Verticle> verticleSupplier, DeploymentOptions options, Handler<AsyncResult<String>> completionHandler) {
boolean closed;
synchronized (this) {
closed = this.closed;
}
if (closed) {
if (completionHandler != null) {
completionHandler.handle(Future.failedFuture("Vert.x closed"));
}
} else {
deploymentManager.deployVerticle(verticleSupplier, options, completionHandler);
}
}
DeploymentOptions:
DataObject(generateConverter = true, publicConverter = false)
public class DeploymentOptions {
public static final boolean DEFAULT_WORKER = false;
public static final boolean DEFAULT_MULTI_THREADED = false;
public static final String DEFAULT_ISOLATION_GROUP = null;
public static final boolean DEFAULT_HA = false;
public static final int DEFAULT_INSTANCES = 1;
private JsonObject config;
private boolean worker;
private boolean multiThreaded;
private String isolationGroup;
private String workerPoolName;
private int workerPoolSize;
private long maxWorkerExecuteTime;
private boolean ha;
private List<String> extraClasspath;
private int instances;
private List<String> isolatedClasses;
private TimeUnit maxWorkerExecuteTimeUnit;
/**
* Default constructor
*/
public DeploymentOptions() {
this.worker = DEFAULT_WORKER;
this.config = null;
this.multiThreaded = DEFAULT_MULTI_THREADED;
this.isolationGroup = DEFAULT_ISOLATION_GROUP;
this.ha = DEFAULT_HA;
this.instances = DEFAULT_INSTANCES;
this.workerPoolName = null;
this.workerPoolSize = VertxOptions.DEFAULT_WORKER_POOL_SIZE;
this.maxWorkerExecuteTime = VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME;
this.maxWorkerExecuteTimeUnit = VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME_UNIT;
}
deploymentManager.deployVerticle:
public void deployVerticle(Supplier<Verticle> verticleSupplier, DeploymentOptions options, Handler<AsyncResult<String>> completionHandler) {
if (options.getInstances() < 1) {
throw new IllegalArgumentException("Can't specify < 1 instances to deploy");
}
if (options.isMultiThreaded() && !options.isWorker()) {
throw new IllegalArgumentException("If multi-threaded then must be worker too");
}
if (options.getExtraClasspath() != null) {
throw new IllegalArgumentException("Can't specify extraClasspath for already created verticle");
}
if (options.getIsolationGroup() != null) {
throw new IllegalArgumentException("Can't specify isolationGroup for already created verticle");
}
if (options.getIsolatedClasses() != null) {
throw new IllegalArgumentException("Can't specify isolatedClasses for already created verticle");
}
//初始化context
ContextInternal currentContext = vertx.getOrCreateContext();
ClassLoader cl = getClassLoader(options);
//將註冊的verticle放入set中,並校驗傳入的verticle是否滿足數量要求
int nbInstances = options.getInstances();
Set<Verticle> verticles = Collections.newSetFromMap(new IdentityHashMap<>());
for (int i = 0; i < nbInstances; i++) {
Verticle verticle;
try {
verticle = verticleSupplier.get();
} catch (Exception e) {
if (completionHandler != null) {
completionHandler.handle(Future.failedFuture(e));
}
return;
}
if (verticle == null) {
if (completionHandler != null) {
completionHandler.handle(Future.failedFuture("Supplied verticle is null"));
}
return;
}
verticles.add(verticle);
}
if (verticles.size() != nbInstances) {
if (completionHandler != null) {
completionHandler.handle(Future.failedFuture("Same verticle supplied more than once"));
}
return;
}
Verticle[] verticlesArray = verticles.toArray(new Verticle[verticles.size()]);
String verticleClass = verticlesArray[0].getClass().getName();
//開始部署
doDeploy("java:" + verticleClass, options, currentContext, currentContext, completionHandler, cl, verticlesArray);
}
VertxImpl.getOrCreateContext:
public ContextImpl getOrCreateContext() {
ContextImpl ctx = getContext();
if (ctx == null) {
// We are running embedded - Create a context
ctx = createEventLoopContext(null, null, new JsonObject(), Thread.currentThread().getContextClassLoader());
}
return ctx;
}
public ContextImpl getContext() {
ContextImpl context = (ContextImpl) context();
if (context != null && context.owner == this) {
return context;
}
return null;
}
public static Context context() {
Thread current = Thread.currentThread();
if (current instanceof VertxThread) {
return ((VertxThread) current).getContext();
}
return null;
}
//創建context EventLoopContext繼承了ContextImpl,這裏保存了這個eventloop所有的信息
//這裏創建EventLoopContext的同時會調用ContextImpl.getEventLoop //從EventLoopGroup中獲取到下一個eventloop並賦予context
@Override
public EventLoopContext createEventLoopContext(String deploymentID, WorkerPool workerPool, JsonObject config, ClassLoader tccl) {
return new EventLoopContext(this, internalBlockingPool, workerPool != null ? workerPool : this.workerPool, deploymentID, config, tccl);
}
ContextImpl.getEventLoop:
private static EventLoop getEventLoop(VertxInternal vertx) {
EventLoopGroup group = vertx.getEventLoopGroup();
if (group != null) {
return group.next();
} else {
return null;
}
}
protected ContextImpl(VertxInternal vertx, WorkerPool internalBlockingPool, WorkerPool workerPool, String deploymentID, JsonObject config,
ClassLoader tccl) {
this(vertx, getEventLoop(vertx), internalBlockingPool, workerPool, deploymentID, config, tccl);
}
protected ContextImpl(VertxInternal vertx, EventLoop eventLoop, WorkerPool internalBlockingPool, WorkerPool workerPool, String deploymentID, JsonObject config,
ClassLoader tccl) {
if (DISABLE_TCCL && tccl != ClassLoader.getSystemClassLoader()) {
log.warn("You have disabled TCCL checks but you have a custom TCCL to set.");
}
this.deploymentID = deploymentID;
this.config = config;
this.eventLoop = eventLoop;
this.tccl = tccl;
this.owner = vertx;
this.workerPool = workerPool;
this.internalBlockingPool = internalBlockingPool;
this.orderedTasks = new TaskQueue();
this.internalOrderedTasks = new TaskQueue();
this.closeHooks = new CloseHooks(log);
}
deploymentManager.doDeploy
private void doDeploy(String identifier,
DeploymentOptions options,
ContextInternal parentContext,
ContextInternal callingContext,
Handler<AsyncResult<String>> completionHandler,
ClassLoader tccl, Verticle... verticles) {
JsonObject conf = options.getConfig() == null ? new JsonObject() : options.getConfig().copy(); // Copy it
String poolName = options.getWorkerPoolName();
Deployment parent = parentContext.getDeployment();
String deploymentID = generateDeploymentID();
DeploymentImpl deployment = new DeploymentImpl(parent, deploymentID, identifier, options);
AtomicInteger deployCount = new AtomicInteger();
AtomicBoolean failureReported = new AtomicBoolean();
for (Verticle verticle: verticles) {
WorkerExecutorInternal workerExec = poolName != null ? vertx.createSharedWorkerExecutor(poolName, options.getWorkerPoolSize(), options.getMaxWorkerExecuteTime(), options.getMaxWorkerExecuteTimeUnit()) : null;
WorkerPool pool = workerExec != null ? workerExec.getPool() : null;
//創建verticle的context 原理和上面的一樣
ContextImpl context = options.isWorker() ? vertx.createWorkerContext(options.isMultiThreaded(), deploymentID, pool, conf, tccl) :
vertx.createEventLoopContext(deploymentID, pool, conf, tccl);
if (workerExec != null) {
context.addCloseHook(workerExec);
}
context.setDeployment(deployment);
deployment.addVerticle(new VerticleHolder(verticle, context));
context.runOnContext(v -> {
try {
verticle.init(vertx, context);
Future<Void> startFuture = Future.future();
verticle.start(startFuture);
startFuture.setHandler(ar -> {
if (ar.succeeded()) {
if (parent != null) {
if (parent.addChild(deployment)) {
deployment.child = true;
} else {
// Orphan
deployment.undeploy(null);
return;
}
}
VertxMetrics metrics = vertx.metricsSPI();
if (metrics != null) {
metrics.verticleDeployed(verticle);
}
deployments.put(deploymentID, deployment);
if (deployCount.incrementAndGet() == verticles.length) {
reportSuccess(deploymentID, callingContext, completionHandler);
}
} else if (failureReported.compareAndSet(false, true)) {
deployment.rollback(callingContext, completionHandler, context, ar.cause());
}
});
} catch (Throwable t) {
if (failureReported.compareAndSet(false, true))
deployment.rollback(callingContext, completionHandler, context, t);
}
});
}
}
DeploymentImpl初始化:
private DeploymentImpl(Deployment parent, String deploymentID, String verticleIdentifier, DeploymentOptions options) {
this.parent = parent;
this.deploymentID = deploymentID;
//Deployment的識別碼(java)
this.verticleIdentifier = verticleIdentifier;
this.options = options;
}
runOnContext:
@Override
public void runOnContext(Handler<Void> task) {
try {
executeAsync(task);
} catch (RejectedExecutionException ignore) {
// Pool is already shut down
}
}
void executeAsync(Handler<Void> task) {
nettyEventLoop().execute(() -> executeTask(null, task));
}
public EventLoop nettyEventLoop() {
return eventLoop;
}