Select 抽象语法树
  打开 SQLSelectStatement 的代码,扫描它的子成员,便分析出这样的一棵语法树:
  这意味着,在 Druid 眼里,它是这样看待一条 Select 语句的所有成员部分的。
  Visitor
  从 demo 代码中可以看到,有了 AST 语法树后,则需要一个 visitor 来访问它
  // 使用visitor来访问AST
  MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
  statement.accept(visitor);
  System.out.println(visitor.getColumns());
  System.out.println(visitor.getOrderByColumns());
  statement 调用 accept 方法,以 visitor 作为参数,开始了访问之旅。在这里 statement 的实际类型是 SQLSelectStatement 。
  在 Druid 中,一条 SQL 语句中的元素,无论是高层次还是低层次的元素,都是一个 SQLObject ,statement 是一种 SQLObject,表达式 expr 也是一种 SQLObject,函数、字段、条件等等,这些都是一种 SQLObject,SQLObject 是一个接口, accept 方法便是它定义的,目的是为了让访问者在访问 SQLObject 时,告知访问者一些事情,好让访问者在访问的过程中能够收集到关于该 SQLObject 的一些信息。
  具体的 accept() 实现,在 SQLObjectImpl 这个类中,代码如下所示:
  public final void accept(SQLASTVisitor visitor) {
  if (visitor == null) {
  throw new IllegalArgumentException();
  }
  visitor.preVisit(this);
  accept0(visitor);
  visitor.postVisit(this);
  }
  这是一个 final 方法,意味着所有的子类都要遵循这个模板,首先 accept 方法前和后,visitor 都会做一些工作。真正的访问流程定义在 accept0() 方法里,而它是一个 抽象方法 。
  因此要知道 Druid 中是如何访问 AST 的,先拿 SQLSelectStatement 的 accept0() 方法来探探究竟。
  protected void accept0(SQLASTVisitor visitor) {
  if (visitor.visit(this)) {
  acceptChild(visitor, this.select);
  }
  visitor.endVisit(this);
  }
  首先,使 visitor 访问自己,访问自己后,visitor 会决定是否还要访问自己的子元素。
  打开 MySqlSchemaStateVisitor 的 visit 方法,可以看到,visitor 做了一些事,初始化了自己的 aliasMap,然后 return true,这意味着还要访问 SQLSelectStatement 的子节点。
  public boolean visit(SQLSelectStatement x) {
  setAliasMap();
  return true;
  }
  接下来访问子元素
  protected final void acceptChild(SQLASTVisitor visitor, SQLObject child) {
  if (child == null) {
  return;
  }
  child.accept(visitor);
  }
  由此可以看出,SQLObject 负责通知 visitor 要访问自己的哪些元素,而 visitor 则负责访问相应元素前,中,后三个过程的逻辑处理。