本文共 1625 字,大约阅读时间需要 5 分钟。
本文继续实践“ ”一文中留下的问题。
问题一:
使用Servlet3.x对Filter类进行注解的时候,如何控制其执行顺序?
首先做个猜测,Filter作为类来组织的,并且使用注解(Annotation)标识。这时候问题来了,WEB容器是如何知道这些Filter的呢?注解标识?
翻看注解public @interface WebFilter:
图b-1
查看了其属性,都具有默认值,也就是说不设置这些值,只需要通过@WebFilter标识后仍然可以作为一个Filter使用,那么也就证明了上面的猜测是不对了,因为这些属性的值没法作为排序的参考。
下面是摘自WebFilter注解的源代码:
String displayName() default "";
/** * @return name of the Filter, if present */ String filterName() default "";
String description() default "";
既然容器是通过注解WebFilter来发现Filter类,那么获得这些类之后如何进行执行顺序的安排则可以不需要依赖注解信息了。在(文一)中程序执行的结果和我们期待的结果达到一致,这恰恰是一个巧合。
EncodingFilter和RequestFilter这两个类的类名字典排序恰恰EncodingFilter在RequestFilter之前。
于是我们有了下面这个测试的案例:
图b-2
图b-3
改变类名,这个时候字典排序RncodingFilter在EequestFilter之后。
下面是运行的结果截图:
图b-4
图b-5
看到上面的图说明这个猜测是正确了,此时先执行了RequestFilter后执行了EncodingFilter。同时我们可以讲图b-5和图a-2(文一)进行对比,浏览器中显示的内容有所不同,也就说明了Filter的执行顺序略微影响到输出内容。当然控制台的打印输出顺序更能说明问题。
但是问题还并没有结束,看到上面用红色标注的内容“两个类的类名”,这两个类的类名应该是全名(即包名+类名)。而(文一)中的EncodingFilter和RequestFilter是处于同一个包的。为什么说是全名呢?自然是有依据的,出于同一个包的EncodingFilter和RequestFilter是没法完全证明“按照Filter类的类名字典顺序执行”这一说明。但是我们可以通过推断,一个包下不可能存在两个同名类,而不同包中可以存在同名类,如何仅仅是按照简单类名的话自然会发生同名Filter的冲突,此刻顺序就没法确定了,因而推断是按类的全名进行排序的。
下面是类的包结构图:
图b-6
图b-7
图b-8
图b-6的包结构是(文一)中的案例采用的。通过实验了图b-7和图b-8的包结构,图b-8中的com.EncodingFilter实际是图b-6中的com.filter.RequestFilter。
图b-7:
字典排序:com.filter.EncodingFilter com.RequestFilter (忽略大小写排序)
图b-9
图b-8:
字典排序:com.EncodingFilter com.filter.EncodingFilter(忽略大小写排序)
图b-10
由于Servlet标准中没有给出这个可以设置参数,这样使得通过注解标识的Filter执行顺序变的复杂,本文仅通过实验来找出这其中的规律推测是按照类名的忽略大小写排序的。实验之中不免存在存问题,或许在使用中又能发现一些问题,当没法准确的判断时,使用web.xml配置可能更加安全一些。
特别遗憾,@WebFilter注解中没有一个属性来完成这件事情。!!!
能力有限,想必文中自然存在不少问题,那位朋友知道这个问题的内部机制,欢迎留言,非常感谢。
转载地址:http://fpkho.baihongyu.com/