纠正:关于@webFilter使用@Order无效问题
2018-08-26 17:58
627 查看
前言
通过
过滤器名称和设置
@Order的方法都是不行的。抱歉了,各位。之后在编写文章时,会本着负责且持着大胆猜测小心求证的态度,会对相关事项进行核对的!再次,抱歉,误导了大家
这里要感谢简书网友:形而上学本尊,指出此错误!再次感谢!
正确设置排序方式
浅谈ServletComponentScan注解的启动方式
总结
最后
老生常谈
正确设置排序方式
先说结论:可以通过
过滤器的类名进行约定排序。
浅谈ServletComponentScan注解的启动方式
既然遇到了,那就简单分析下使用
@WebFilter和
@ServletComponentScan的启动方式吧。
首先我们来看下,注解
@ServletComponentScan(删除了相关注解):
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ServletComponentScanRegistrar.class) public @interface ServletComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
简单来说,此注解就是指定扫描路径的,通过
value、
basePackages或者
basePackageClasses。主要还是看下
ServletComponentScanRegistrar类,这才是关键。
class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar { private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor"; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 获取包路径 Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); // 若已注册,则更新,否则新增 if (registry.containsBeanDefinition(BEAN_NAME)) { updatePostProcessor(registry, packagesToScan); } else { addPostProcessor(registry, packagesToScan); } } private void updatePostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) { BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME); ValueHolder constructorArguments = definition.getConstructorArgumentValues().getGenericArgumentValue(Set.class); @SuppressWarnings("unchecked") Set<String> mergedPackages = (Set<String>) constructorArguments.getValue(); mergedPackages.addAll(packagesToScan); constructorArguments.setValue(mergedPackages); } private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); // 设置类 beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class); // 设置构造函数参数 beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册 registry.registerBeanDefinition(BEAN_NAME, beanDefinition); } private Set<String> getPackagesToScan(AnnotationMetadata metadata) { // 获取注解ServletComponentScan的属性信息 AnnotationAttributes attributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(ServletComponentScan.class.getName())); // 获取属性basePackages和basePackageClasses String[] basePackages = attributes.getStringArray("basePackages"); Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses"); Set<String> packagesToScan = new LinkedHashSet<String>(); packagesToScan.addAll(Arrays.asList(basePackages)); // basePackageClasses 最后也是根据basePackageClasses来获取塔对应的包路径 for (Class<?> basePackageClass : basePackageClasses) { packagesToScan.add(ClassUtils.getPackageName(basePackageClass)); } // 默认不填写时,获取的是被注解类所在包路径,所以一般放在启动类上 if (packagesToScan.isEmpty()) { packagesToScan.add(ClassUtils.getPackageName(metadata.getClassName())); } return packagesToScan; } }
可以看见,它是一个
ImportBeanDefinitionRegistrar的实现类,
ImportBeanDefinitionRegistrar可以动态地装载
Bean。再来看看
ServletComponentRegisteringPostProcessor类,此类是个
BeanFactoryPostProcessor,BeanFactory的后置处理器,简单理解就是扩展点吧。启动的时候会调用
postProcessBeanFactory方法。
ServletComponentRegisteringPostProcessor源码就不贴了,简单来说,它的作用就是:扫描被
@WebServlet、
@WebFilter及
@WebListener的类,最后通过对应的
ServletRegistrationBean、
FilterRegistrationBean及
ServletListenerRegistrationBean进行注册。看见这些是不是很熟悉了。
//部分代码 static { List<ServletComponentHandler> servletComponentHandlers = new ArrayList<ServletComponentHandler>(); servletComponentHandlers.add(new WebServletHandler()); servletComponentHandlers.add(new WebFilterHandler()); servletComponentHandlers.add(new WebListenerHandler()); HANDLERS = Collections.unmodifiableList(servletComponentHandlers); }
关键看这个方法
scanPackage:
private void scanPackage( ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan) { for (BeanDefinition candidate : componentProvider .findCandidateComponents(packageToScan)) { if (candidate instanceof ScannedGenericBeanDefinition) { for (ServletComponentHandler handler : HANDLERS) { handler.handle(((ScannedGenericBeanDefinition) candidate), (BeanDefinitionRegistry) this.applicationContext); } } } }
可以看见,通过
componentProvider.findCandidateComponents(packageToScan)方法获取到对应的注解类,同时判断是否为以上说的三种,最后调用其
doHandle方法完成注册功能。以下是
WebFilterHandler的
doHandler方法。
现在,我们看看
findCandidateComponents方法怎么获取对应注解类的。
断点之后,可以看见是
AnnotationConfigEmbeddedWebApplicationContext类,
继续断点进去,最后是使用
PathMatchingResourcePatternResolver类进行资源获取的。
通过递归的方式,获取所有的类:
最后关键就是这个
Arrays.sort(dirContents)了。所以简单来说,可以通过class类名来达到排序效果。但这种方案要限制类名,还是使用
FilterRegistrationBean之类的来设置吧。
总结
写的可能有点乱也有点水,⊙﹏⊙‖∣。主要还是想纠正下原先的错误,O__O…。知其然知其所以然,还有很长的路要走。没有写里面的细节,只是大致讲解了下。有兴趣的可以自行跟踪看看。
最后
目前互联网上很多大佬都有
SpringBoot系列教程,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。
老生常谈
个人QQ:499452441
微信公众号:
lqdevOps
个人博客:http://blog.lqdev.cn
原文地址:http://blog.lqdev.cn/2018/08/26/%E6%97%A5%E5%B8%B8%E7%A7%AF%E7%B4%AF/correct-webfilter/
相关文章推荐
- 纠正:关于@webFilter使用@Order无效问题
- 关于使用maskbarcode在WEB页面中生成一维条形码的问题
- 关于web项目中使用sigar的问题(服务器为weblogic)
- 1.关于Web.config之间不能使用&字符的问题
- 关于System.Web.Script.Serialization.JavaScriptSerializer序列化的数据再Mongodb.CSharp中使用问题
- 关于DAL层使用静态方法,并在WEB层直接调用的问题
- 关于WPF中TextBox使用SelectAll无效的问题的解决办法
- 关于easyui中的combogrid keyHanlder属性使用的问题(filter改进)
- 安卓开发_关于WebView使用链接时调用浏览器显示的问题
- 关于使用myeclipse创建web项目中可能出现的问题
- 在WEB程序中使用.NET Remoting的IpcChannel时注意事项(关于“拒绝访问”问题的解决)
- 关于android的webview 使用的问题 JS无法正常使用 界面切换出现白屏
- 关于ie6中使用css滤镜[_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/*.png',sizingMethod='scale')]后链接无法点击的问题
- JAVA Web 安全机制----使用filter验证session用户和页面缓存问题处理
- 关于使用Yii框架开发时数据库增加字段后保存无效的问题
- 关于4.4以上手机 webview 中设置 singleColumn无效的问题
- 关于Java Web开发中Servlet使用Servlet接口的问题
- 关于WebValidates.dll验证控件在VS2008和VS2010中使用的问题
- 关于使用ISA SERVER禁用WEB登陆邮箱的问题