1、先看源码中类ServletContextInitializerBeans初始化的过程
- 构造方法
public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
Class extends ServletContextInitializer>... initializerTypes) {
... //省略非相关代码
addServletContextInitializerBeans(beanFactory);
addAdaptableBeans(beanFactory);
List sortedInitializers = this.initializers.values().stream()
.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
.collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
logMappings(this.initializers);
}
- 查看构造方法中调用的方法addAdaptableBeans(beanFactory);
protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
...... //省略非相关代码
}
可以看到实现Filter.class的bean注入主要是通过addAsRegistrationBean(beanFactory, Filter.class, new
FilterRegistrationBeanAdapter());这段代码实现的
- 继续查看方法addAsRegistrationBean
protected void addAsRegistrationBean(ListableBeanFactory beanFactory, Class type,
RegistrationBeanAdapter adapter) {
addAsRegistrationBean(beanFactory, type, type, adapter);
}
private void addAsRegistrationBean(ListableBeanFactory beanFactory, Class type,
Class beanType, RegistrationBeanAdapter adapter) {
List> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
...... //省略非相关代码
}
- 继续查看方法getOrderedBeansOfType,此方法实现了filter的排序功能
private List> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class type,
Set> excludes) {
String[] names = beanFactory.getBeanNamesForType(type, true, false);
Map map = new LinkedHashMap<>();
for (String name : names) {
if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
T bean = beanFactory.getBean(name, type);
if (!excludes.contains(bean)) {
map.put(name, bean);
}
}
}
List> beans = new ArrayList<>(map.entrySet());
beans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue())); //实现filter的排序功能
return beans;
}
- 继续查看AnnotationAwareOrderComparator的compare方法
public int compare(@Nullable Object o1, @Nullable Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
//判断是否实现优先排序接口,若其中一个实现另一个未实现则可直接返回优先级
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
//均实现优先排序接口或均未实现排序接口
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
大致的意思就是从BeanFactory中获取到filter对应的bean,使用
AnnotationAwareOrderComparator类进行比较排序,接下来再看看排序的细节。
2、Ordered接口与@Order注解的解读
从源码中可以看出使用
AnnotationAwareOrderComparator对filter的排序是通过对实现了Ordered接口、@Order注解的解析出order值完成排序,如果两个都定义了的话优先取实现接口Ordered的排序值,示例如下:
@Order(20)
class DemoOrder implements Ordered{
@Override
public int getOrder() {
return 10;
}
}
DemoOrder中既实现了Ordered接口也定义了@Order注解,其结果是取10,实现接口的优先判断返回,查看findOrder源码可以看到如果能从实现接口中获取到排序就已return返回了
- AnnotationAwareOrderComparator的findOrder
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
3、自定义Filter的两种方式
- 3.1、使用@Component注册为普通的RegistrationBean
@Order(10)
@Component
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
}
- 3.2、使用@Webfilter注解以及@ServletComponentScan注解
@WebFilter
public class DemoWebFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
}
//需同时在启动类中加入@ServletComponentScan
需注意,在使用@Webfilter注解时,若使用了@Order或继承了Ordered接口均无法改变Filter的顺序的,只能改变类的命名调整Filter的顺序
- 3.3、分析@Webfilter增加@Order注解或实现Ordered接口无效原因
我们回看类
ServletContextInitializerBeans的构造方法中的
addServletContextInitializerBeans(beanFactory);可以跟踪到若使用@Webfilter注册的bean,其order值相同均为默认优先级最低值order=2147483647,是由
AnnotationAwareOrderComparator类的findOrder方法获取,那为什么不会获取到类中定义的实现Ordered的接口呢?接着分析一下类的注册过程
- 3.4、addAdaptableBeans(beanFactory);方法获取FilterRegistrationBean是通过ServletContextInitializerBeans的方法addAsRegistrationBean,如下
private void addAsRegistrationBean(ListableBeanFactory beanFactory, Class type,
Class beanType, RegistrationBeanAdapter adapter) {
// 省略非关键代码
RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
int order = getOrder(bean);
registration.setOrder(order); //获取到order值重新设置
this.initializers.add(type, registration);
// 省略非关键代码
}
}
}
- 3.5、addServletContextInitializerBeans(beanFactory);方法获取FilterRegistrationBean是通过AbstractBeanFactory类的方法,如下
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
// 省略非关键代码
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
// 省略非关键代码
}
}
可以看到两种方式的不同,addAsRegistrationBean重新设置了order排序
如果使用了Ordered接口或者@Order注解,则按优先级排序,如果没有则排到最后,如果有多个没有Order的接口,则按类名的字典排序。