在使用软件的时候,你一定遇到过版本需要更新,以便于使用更多的新特性。像微信这样,旧版本可能只能摇一摇,新版本就可以录小视频了。这种情况下,你肯定就很乐意升级。
对于Tomcat,也存在同样的情况。可能旧版本的Tomcat只支持到Servlet2.5,新版的可能就支持Servlet3.0了,而且还支持异步的Servlet,支持注解声明Servlet,支持通过编程的方式,动态的添加或删除Servlet,支持Comet……
这么多的新特性,你一定跃跃欲试。
马不停蹄的下载了新版本,安装,部署应用。
之后,就傻眼了。
应用的页面都显示不出来了啊!!!
这是什么原因,上一个版本还好好的呀。是不是哪里配置错了?
你又认认真真的检查了各个文件。重新启动,问题依旧。
这个时候,你想到了去Google一下,看看别人有没有遇到同样的问题。
查了不少帖子,找到了一些配置,问题可能马马虎虎的解决了。一回头,你又去忙别的了。
其实,Tomcat也是个很贴心的小朋友。其实你可以在一动手前,可以Google "Tomcat upgrade",不出意料,第一篇就是官方提供的名为“Migration Guides”的网页,包含从5.5一直升级到8.0需要注意的事项。
开篇的提醒就很赞,我大致归纳了一下:
注意JVM的版本,有些不兼容,但目前都支持JDK8
大版本升级到一个新的大版本时,不要通过拷贝原来的配置文件来设置,可能各个属性都已经不通用了。最好在新的版本的配置中按照需要再单独配置。
小版本的升级,可以直接使用原来的配置文件,但可能一些配置项的默认值发生了变化,需要注意。
我们在升级Tomcat时,最容易遇到的问题,第一是需要同步升级JDK,第二可能就是语法方面的要求更加的严格了。
例如从Tomcat6升级到Tomcat7,最常见的则是jsp中的EL表达式可以解析不正确,甚至导致页面渲染不成功,这就是语法检查更严格导致的。
例如下面的表达式
<c:set var="class" value="${i.index%2==0?'':'class=bg'}" />
你想要声明一个叫为class的变量,来控制页面表格的样式,这在Tomcat6没有问题,但升级后就会有问题,而修改为其它名称后,可以正常解析。
这里tomcat 7对EL表达式的语法要求比较严格,所检查的,是所使用的这个变量名称,是否为java的关键字。例如"${owner.new}"因包含关键字new就会导致解析出错。
问题是出来了,怎么解决呢?一般Tomcat为了兼容,都会做一个小开关,可以通过配置解决。
对于上面的问题,有三种解决方式,如下:
严格遵守java规范,修改对象的属性名称,按要求不包含java关键字;
修改EL表达式,例如"${owner.new}"可以修改为"${owner['new']}";
修改tomcat属性,忽略对EL表达式的关键字检查。修改$CATALINA_BASE/conf/catalina.properties文件,添加org.apache.el.parser.SKIP_IDENTIFIER_CHECK=true选项。
对于第三种方式,这个属性是跳过检查的配置。我们再来看下源码中大概是怎么判断的。
/**
* Test whether a string is a Java identifier. Note that the behaviour of
* this method depend on the system property
* {@code org.apache.el.parser.SKIP_IDENTIFIER_CHECK}
*/
public static boolean isIdentifier(String key) {
if (SKIP_IDENTIFIER_CHECK) { //注意这里,如果配置就会跳出了。
return true;
}
// Check the list of known invalid values
int i = 0;
int j = invalidIdentifiers.length;
while (i < j) {
int k = (i + j) >>> 1; // Avoid overflow
int result = invalidIdentifiers[k].compareTo(key);
if (result == 0) {
return false;
}
if (result < 0) {
i = k + 1;
} else {
j = k;
}
}
// Check the start character that has more restrictions
if (!Character.isJavaIdentifierStart(key.charAt(0))) {
return false;
}
// Check each remaining character used is permitted
for (int idx = 1; idx < key.length(); idx++) {
if (!Character.isJavaIdentifierPart(key.charAt(idx))) {
return false;
}
}
return true;
}
}
我们看到上面代码,先判断是否配置跳过检查,如果没有,则会和系统中的关键字List逐一比对,确认是否重名。
如果感觉有用,请转到朋友圈,让更多朋友了解。