Tomcat运行时类载入或查找顺序

  • Tomcat自定义载入器(一般为WebappClassLoader)本地缓存及ClassLoader缓存
  • Bootstrap class loader载入(在其安全目录内)
  • Extension class loader载入(在其安全目录内,比如这里为:$JAVA_HOME/jre/lib/ext/*.jar )
  • System class loader (在其安全目录内,比如这里为:CLASSPATH/)
    注意:以上要优先主要是基于安全,避免类似自定义java.lang.Object优先于JDK的java.lang.Object被加载
  • /WEB-INF/classes/*.class
  • /WEB-INF/lib/*.jar 这里面按包名的字典顺序去加载
  • $CATALINA_HOME/common/classes
  • $CATALINA_HOME/common/endorsed/*.jar
  • $CATALINA_HOME/common/i18n/*.jar
  • $CATALINA_HOME/common/lib/*.jar
  • $CATALINA_BASE/shared/classes
  • $CATALINA_BASE/shared/lib/*.jar

由于类加载器对于同名(包括包路径)的类只会加载一次所以我们可以采取些手段去改变一个类的行为

比如我们想做这么一件事 在ibatis 启动的时候我们需要检查一下sqlmap 中是不是存在注入的风险

  • 首先我们可以重写com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate 的 addMappedStatement方法 用正则去匹配可能存在注入风险的sql如果存在则抛异常。当然这只是最原始最野蛮的一个办法
  • 其次我们可以将这个类单独放在一个jar包里 为了达到优先加载的目的 我们可以将jar包的名字以 _ 开头 这样就可先于 ibatis jar包里面原来的类加载
  • 同样是这样的jar我们可以放到更前一步 比如$JAVA_HOME/jre/lib/ext 目录下
  • 甚至我们可以使用java agent 通过jdk 的 Instrumentation 配合asm完成,当然这个就要求开发人员对 class 文件结构有一定的了解