java攻城狮基础-总纲

java是一门语法相对简单的流行语言,学习曲线比较低,很多童鞋做了太久的CRUD,误以为自己已经对java相当熟悉。其实,我们说的java,不单单是java语法,还包括java惯用法,常见jdk库的细节,jvm相关的基础知识,常见周边框架原理等,是一个大的体系,并不容易掌握。

我计划写一系列的基础文章,一方面看看自己掌握程度如何,查漏补缺,另一方面是看看自己能不能把重点说清楚,当作一次重新学习的机会。

我先简单整个列表,包括一些常见的基础性话题,后续再进行根据情况调整。写作形式以小文章为主,争取半小时以内可以理解的内容,并附带一些思考题。

  • 面向对象特征,包括封装,继承,多态
  • 原生类型与包装类型,原生类型是其他结构的基础,识别两者在内存上的区别,开封箱特性,了解包装类型的实现,如特定整型对象的缓存。
  • 匿名类、内部类、静态内部类,了解他们之间的区别,还有编译后的实际结构(如何转换为普通类)。
  • 可变长参数与数组参数,了解可变长参数在编译层面的实现,了解存在重载情况下可能的混淆问题。
  • 内部变量初始化、构造方法、静态变量初始化、静态块、及存在继承关系时的执行顺序,原则:父类优先,静态常量优于静态块
  • equals,hashcode用途,实现原则,hashcoe要实现简单,和equals保持一致,equals要确保自反性,对称性,传递性,一致性。了解hashcode和equals的应用场景。
  • 对象的强、软、弱和虚引用,了解各种引用的区别及应用场景 http://www.importnew.com/20468.html
  • 常见集合类的特性,应该能够在实际作用中灵活使用,掌握区别及实现原理,列表(ArrayList Vector LinkedList Queue Stack Deque PriorityQueue),散列(HashMap LinkedHashMap TreeMap IdentityHashMap EnumMap WeakHashMap HashTable SortedMap),集合(HashSet TreeSet EnumSet) 需要整理一个特性比较的表格 待整理
  • 多线程基础 java线程模型,线程生命周期,sleep,wait,notify,notifyall,join等线程通信机制。理解同步,原子性,可见性,CAS无锁机制等概念,了解常见锁类型。
  • 并发工具类,掌握常见并发工具类的特性,使用场景,使用方法。了解相关的实现原理。主要包括Executor,Atomic类,ConcurrentHashMap,CopyOnWriteArrayList,BlockingQueue,Latch,Barrier,Condition,Lock等等
  • 擦除型泛型,上限,下限,掌握泛型的作用,如何保持旧代码兼容
  • String、StringBuffer和StringBuilder类的应用场景,区别
  • 正则表达式,掌握常见正则表达式写法,了解正则表达式实现
  • Checked异常和Runtime异常体系,异常的性能,实践中异常的设计与统一处理,包括安全性设计
  • 字符,字节,io流,掌握java流设计体系,字符编码相关知识点,编码转换特性
  • 序列化,序列化应用场景,性能,安全性方面
  • java8最新特性 http://m.open-open.com/m/lib/view/1403232177575.html#methodReferences

认真看待java web基础

很多人一开始接触java技术,做的项目都是web相关的,搞过servlet,jsp,struts,springmvc,用过tomcat,终于感觉是web开发没什么问题了,简历可以标上熟悉java web开发。

现在我们从基本的war包开始,重新梳理一下java web基础,权当复习。

曾经我面试问一个小问题,你知道war包是怎样的结构么?有人会说有src,还有webroot,webapp之类的目录,有人说有平级的classes和WEB-INF目录.

最常见的格式是这样的

xx.war
  WEB-INF
    classes
      com/xxx/A.class
      conf
         xx.properties
      log4j.xml
    lib
      *.jar
    web.xml
  *.jsp

可以看到是没有源代码的。那么

  • 传说中java的class文件可以一次编译到处运行,那么源代码采用GBK还是UTF-8会有影响么?
  • 如果lib有2个不同版本的jar,例如spring2.5,spring3,还能安心干活么?
  • 如果classes有个class文件不小心被打到jar包去,遗忘在lib目录,以后更新classes会不会炸了?
  • log4j.xml放到conf目录会有问题么? 有什么区别没有?
  • 有人写了个Niubility的类放在yy.war, 为什么我就调用不到呢,明明同一个猫上跑的?
  • 听说有servlet3支持异步可厉害了,但放个demo到tomcat6会挂了,我lib明明有高大上的servlet-api.jar?
  • 听说web.xml里边可以配置监听器listener,但它监听什么?
  • 为什么不建议把jsp放在war的根目录下?

如果可以轻松无压力,那么说明java web基础还是可以的。

@首发于公司内部群组

一次INTERNAL_SERVER_ERROR的问题分析

问题现象

晚上版本上线后,发现工号进入首页后页面空白,显示INTERNAL_SERVER_ERROR

过程回顾

  1. 通过fiddler抓包,发现某个请求出现500错误
  2. 检查应用,was,ihs日志,没有发现有效日志
  3. 发现只有部分工号有问题,开始怀疑存在数据问题,准备导数据回测试环境验证
  4. 同时,新建一套ihs和was环境进行验证
  5. 新环境验证,发现原来失败的工号可以正常,怀疑环境配置有问题。同时发现请求超过4s就会返回500错误
  6. 尝试直接访问原was,发现是正常的
  7. 对比两个环境配置,was和ihs配置是一样的,但plugins-in参数ServerIOTimeout有差异,旧的是-1,新的为0
  8. 修改新的为-1,访问问题重现
  9. 准备修改为0,问题修复

技术分析

关于ServerIOTimeout参数的描述,可以参考以下链接。

取值为负数的情况,描述如下:

ServerIOTimeout value can be either positive or negative. If positive, when the ServerIOTimeout pops, the plug-in will not mark that server down. If negative, when the ServerIOTimeout pops, it will mark that server down. If your application uses HttpSession object, then there will be session affinity in play, so it would be best to choose a negative ServerIOTimeout value, to ensure that the retry will not be sent back to the same server that just timed-out. Since that server will be marked down, the retry will go to a different appserver in the cluster.

简单来说,关于参数的取值都是需要权衡的。ServerIOTimeout表示ihs和was之间连接的读写超时时间,取值有三种值:

  • 0 表示一直等待was响应,这样可能会造成长时间不响应,连接也不释放
  • 正数 表示读写超时时间,超时之后会重试,这样可能会造成业务重复受理
  • 负数 和正数一样,不过超时之后会认为当前was为下线状态,然后重试其他服务器,对于无状态的请求同样可能有重复受理的问题。在上面的问题中,ihs后面有4个was,所以刚好看上去就是超过4s会超时

小总结

  • 优化应用日志很重要,特别是那些没什么用的异常日志,需要定期优化现网日志
  • 最小化的可重现问题的环境
  • 熟悉常见调试工具,如fiddler,telnet,wget,curl,tcpdump等
  • 修改参数应该慎重,知道参数的含义,不要想当然。这次就是以为-1和0是没有区别

tidb源码学习之auto_increment

自增ID

TiDB 的自增 ID (Auto Increment ID) 只保证自增且唯一,并不保证连续分配。 TiDB 目前采用批量分配的方式,所以如果在多台TiDB上同时插入数据,分配的自增 ID 会不连续。

https://github.com/pingcap/tidb/tree/master/meta/autoid/autoid.go

基本接口

// Allocator is an auto increment id generator.
// Just keep id unique actually.
type Allocator interface {
	// Alloc allocs the next autoID for table with tableID.
	// It gets a batch of autoIDs at a time. So it does not need to access storage for each call.
	Alloc(tableID int64) (int64, error)
	// Rebase rebases the autoID base for table with tableID and the new base value.
	// If allocIDs is true, it will allocate some IDs and save to the cache.
	// If allocIDs is false, it will not allocate IDs.
	Rebase(tableID, newBase int64, allocIDs bool) error
}

接口很简单,一个是根据tableID分配一个自增ID,而且分配是批量进行的,所以还有另一个是用来重新设置批量获取的起始点。

type allocator struct {
	mu    sync.Mutex
	base  int64
	end   int64
	store kv.Storage
	dbID  int64
}

从实现类的结构可以看出实现的基本思路。mu是用于并发分配操作的锁,base表示最后一个已分配的ID,end表示最后一个未分配的ID。 当base和end相等的时候,就表示当前自增ID已经使用完,需要重新发起一次批量申请了。store表示后端的存储引擎,dbID表示表所在的数据库。

		err := kv.RunInNewTxn(alloc.store, true, func(txn kv.Transaction) error {
			m := meta.NewMeta(txn)
			var err1 error
			newBase, err1 = m.GetAutoTableID(alloc.dbID, tableID)
			if err1 != nil {
				return errors.Trace(err1)
			}
			newEnd, err1 = m.GenAutoTableID(alloc.dbID, tableID, step)
			if err1 != nil {
				return errors.Trace(err1)
			}
			return nil
		})

至于如何从store获取到当前的未分配的自增ID,首先通过GetAutoTableID获取到当前最后一个已分配的ID,然后通过GenAutoTableID获取一个批次的ID。

tidb源码学习之ast包

基本结构 ast.go

基本结构

基本实现 base.go

和上图很类似,只是属于内部实现,提供了基本的能力,用于更细化的类型实现。 基本实现

函数调用 functions.go

分别为聚合函数,普通函数,转换函数

函数调用

可视化AST

为了方便理解AST,需要有个简单的可视化工具。

type astViewer struct {
	level int
}

// Enter implements ast.Visitor interface.
func (av *astViewer) Enter(inNode ast.Node) (outNode ast.Node, skipChildren bool) {
	fmt.Println(strings.Repeat("  ", av.level), reflect.TypeOf(inNode))
	av.level++
	return inNode, false
}

// Leave implements ast.Visitor interface.
func (av *astViewer) Leave(inNode ast.Node) (node ast.Node, ok bool) {
	av.level--
	return inNode, true
}

// How to use it.
node.Accept(&astViewer{})

DML语句 dml.go

dml语句类型

dml语句类型

dml语句还有不少内部结构,简单分类一下:

字段相关部分,其中WildCardField是一种特殊的SelectField,FieldList包括多个SelectField

字段

表相关部分,其中从外到里关系是TableRefsClause - Join - TableSource - TableName

表

条件相关部分,就不解释了

条件

DDL语句 ddl.go

ddl

表达式语句 expression.go

函数 functions.go

系统管理语句 misc.go