我们知道帆软Report本质是一个web项目,所以他也有filter,servelt。当一个请求来到时,先经过filter,然后再经过servlet。
第一步,要经过的filter:
帆软报表内部加了7个filter。他们分别是:
ApplicationFilterConfig
ApplicationFilterConfig
ApplicationFilterConfig
ApplicationFilterConfig
ApplicationFilterConfig
ApplicationFilterConfig
ApplicationFilterConfig
这些filter是在com.fr.decision.base.DecisionServletInitializer上添加的,DecisionServletInitializer其实就是一个Activator,看了前面的文章知道Activator是个什么东西。
在DecisionServletInitializer的start方法中:
public void start() {
ServletContext servletContext = (ServletContext)this.getModule().upFindSingleton(ServletContext.class);
if (servletContext != null) {
AnnotationConfigWebApplicationContext context = (AnnotationConfigWebApplicationContext)this.getModule().upFindSingleton(AnnotationConfigWebApplicationContext.class);
context.register(new Class{DecisionHandlerAdapter.class});
this.initUrlEncodeStyle(servletContext);
this.listenGlobalServletFilter(servletContext);
Dynamic servlet = servletContext.addServlet(ServerConfig.getInstance().getServletName(), new DispatcherServlet(context));
servlet.addMapping(new String{ServerConfig.getInstance().getServletMapping()});
servlet.setLoadOnStartup(1);
servlet.setAsyncSupported(true);
this.listenEmbedServletFilter(servletContext);
this.addCounterFilter(servletContext);
this.addPluginStoreFilter(servletContext);
this.addTenantFilter(servletContext);
SateVariableManager.put("fineContextPath", servletContext.getContextPath());
SateVariableManager.put("fineServletURL", servletContext.getContextPath() + "/" + ServerConfig.getInstance().getServletName());
context.register(new Class{DecisionConfiguration.class});
FineLoggerFactory.getLogger().info("Server started with build: {}", new Object{GeneralUtils.readFullBuildNO()});
}
}
其中的:
this.listenGlobalServletFilter(servletContext);
this.listenEmbedServletFilter(servletContext);
this.addCounterFilter(servletContext);
this.addPluginStoreFilter(servletContext);
this.addTenantFilter(servletContext);
都是跟filter相关的。
1 先来看listenGlobalServletFilter
private void listenGlobalServletFilter(ServletContext servletContext) {
Set<GlobalRequestFilterProvider> set = ExtraDecisionClassManager.getInstance().getArray("GlobalRequestFilterProvider");
Set<GlobalRequestFilterProvider> sort = new TreeSet(set);
Iterator var4 = sort.iterator();
while(var4.hasNext()) {
final GlobalRequestFilterProvider provider = (GlobalRequestFilterProvider)var4.next();
String externalFilterClassName = provider.externalFilterClassName();
javax.servlet.FilterRegistration.Dynamic servletFilter;
if (StringUtils.isBlank(externalFilterClassName)) {
servletFilter = servletContext.addFilter(provider.filterName(), new javax.servlet.Filter() {
public void init(FilterConfig filterConfig) throws ServletException {
provider.init(filterConfig);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
provider.doFilter((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse, filterChain);
}
public void destroy() {
provider.destroy();
}
});
} else {
servletFilter = servletContext.addFilter(provider.filterName(), externalFilterClassName);
}
Map<String, String> parameters = provider.initializationParameters();
if (parameters != null) {
servletFilter.setInitParameters(provider.initializationParameters());
}
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR);
servletFilter.addMappingForUrlPatterns(dispatcherTypes, false, provider.urlPatterns());
}
}
可以看出先从我们的扩展GlobalRequestFilterProvider中取出所有插件的这种扩展。然后遍历每个扩展,如果扩展的externalFilterClassName为空,那么创建一个内部filter,在内部filter中再来调用我们provider中的init,doFilter,destory方法,说明我们的provider不是一个标准的filter类。如果externalFilterClassName不为空,意思就是我们可以提供一个标准的filter,在这里将filter全类名赋给externalFilterClassName,那么就会将我们的标准filter加进来。并且将provider提供的initParams传递到标准filter中。
2 看listenEmbedServletFilter:
private void listenEmbedServletFilter(ServletContext servletContext) {
final Set<EmbedRequestFilterProvider> set = new LinkedHashSet(ExtraDecisionClassManager.getInstance().getArray("EmbedRequestFilterProvider"));
Filter<PluginContext> filter = new Filter<PluginContext>() {
public boolean accept(PluginContext context) {
return context.contain(PluginModule.ExtraDecision, "EmbedRequestFilterProvider");
}
};
EventDispatcher.listen(PluginEventType.AfterRun, new Listener<PluginContext>() {
public void on(Event event, PluginContext context) {
Set<EmbedRequestFilterProvider> providers = context.getRuntime().get(PluginModule.ExtraDecision, "EmbedRequestFilterProvider");
set.addAll(providers);
}
}, filter);
EventDispatcher.listen(PluginEventType.BeforeStop, new Listener<PluginContext>() {
public void on(Event event, PluginContext context) {
Set<EmbedRequestFilterProvider> providers = context.getRuntime().get(PluginModule.ExtraDecision, "EmbedRequestFilterProvider");
set.removeAll(providers);
}
}, filter);
javax.servlet.FilterRegistration.Dynamic servletFilter = servletContext.addFilter(ServerConfig.getInstance().getServletName(), new javax.servlet.Filter() {
public void init(FilterConfig filterConfig) {
Iterator var2 = set.iterator();
while(var2.hasNext()) {
EmbedRequestFilterProvider one = (EmbedRequestFilterProvider)var2.next();
one.init(filterConfig);
}
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Iterator var4 = set.iterator();
while(var4.hasNext()) {
EmbedRequestFilterProvider one = (EmbedRequestFilterProvider)var4.next();
one.filter((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
}
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
Iterator var1 = set.iterator();
while(var1.hasNext()) {
EmbedRequestFilterProvider one = (EmbedRequestFilterProvider)var1.next();
one.destroy();
}
}
});
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR);
servletFilter.addMappingForUrlPatterns(dispatcherTypes, false, new String{ServerConfig.getInstance().getServletMapping()});
}
可以看出这里创建一个内部filter,我们的扩展EmbedRequestFilterProvider是在内部filter调用的。
下一个 addCounterFilter:
private void addCounterFilter(ServletContext servletContext) {
javax.servlet.FilterRegistration.Dynamic servletFilter = servletContext.addFilter("counter", new OncePerRequestFilter() {
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String sessionID = WebUtils.getHTTPRequestParameter(httpServletRequest, "sessionID");
try {
AccessContext.getRequest().inc();
if (sessionID != null) {
AccessContext.getSessionRequest().inc();
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
} finally {
AccessContext.getRequest().dec();
if (sessionID != null) {
AccessContext.getSessionRequest().dec();
}
}
}
});
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR);
servletFilter.addMappingForUrlPatterns(dispatcherTypes, false, new String{ServerConfig.getInstance().getServletMapping()});
}
可以看出这是一个统计的filter。
下一个addPluginStoreFilter:
private void addPluginStoreFilter(ServletContext servletContext) {
javax.servlet.FilterRegistration.Dynamic servletFilter = servletContext.addFilter("plugin-store-filter", new PluginStoreFilter());
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR);
servletFilter.addMappingForUrlPatterns(dispatcherTypes, false, new String{"/scripts/*", "/upm/*"});
}
这是一个扩展插件里的js资源的filter。
下一个addTenantFilter:
private void addTenantFilter(ServletContext servletContext) {
javax.servlet.FilterRegistration.Dynamic tenantFilter = servletContext.addFilter(TenantFilter.class.getSimpleName(), TenantFilter.getInstance());
tenantFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR), false, new String{"/*"});
}
这个暂时还没看出是干啥的。
当这些filter都通过后,下一步进入servlet。
第二部:经过servlet:
servelt注册也是在com.fr.decision.base.DecisionServletInitializer中注册的:
Dynamic servlet = servletContext.addServlet(ServerConfig.getInstance().getServletName(), new DispatcherServlet(context));
servlet.addMapping(new String{ServerConfig.getInstance().getServletMapping()});
servlet.setLoadOnStartup(1);
servlet.setAsyncSupported(true);
对,就是DispatcherServlet。
在DispatcherServlet的doDispatch方法中有几行代码分别对请求进行某些处理:
mappedHandler.applyPreHandle(processedRequest, response) //预先处理
mappedHandler.applyPostHandle(processedRequest, response, mv) //正式处理
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response)
只有 applyPreHandle成功后才会进行后面的。
下面介绍applyPreHandle,
applyPreHandle方法会调用HandlerExecutionChain的applyPreHandle,来看看它的整个方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors;
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
可以看到这里会获取一些Interceptors来,最终都是调用Interceptors的preHandle。内部默认有这12个Interceptor拦截器。
这里比较重要的interceptor有:
RequestPreHandleInterceptor:
它里面有扩展RequestPreHandleProvider,看看它的preHandle:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
Set<RequestPreHandleProvider> providers = ExtraDecisionClassManager.getInstance().getArray("RequestPreHandleProvider");
Iterator var5 = providers.iterator();
while(var5.hasNext()) {
RequestPreHandleProvider provider = (RequestPreHandleProvider)var5.next();
if (provider.accept(request)) {
return provider.preHandle(request, response);
}
}
} catch (Exception var7) {
FineLoggerFactory.getLogger().error(var7.getMessage(), var7);
}
return true;
}
,可以看到这里会调用扩展RequestPreHandleProvider的 accept,preHandle处理请求。系统内部实现了两个provider,Html5URLRedirectProvider,Html5HeaderHandlerProvider.
DecisionInterceptor:
它里面虽然没有扩展,但是可以通过 PreHandlerFactory.getInstance().registerRequestCheckers(RequestChecker checker)来注册RequestChecker来对请求进行出来,来看他的preHandle,
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
EventDispatcher.fire(RequestBeginEndEvent.REQUEST_BEGIN, new RequestBeginEndEventInfo(request, response));
HandlerMethod handlerMethod = (HandlerMethod)handler;
RequestChecker checker = PreHandlerFactory.getInstance().getRequestChecker(request, handlerMethod);
return checker.checkRequest(request, response, handlerMethod);
}
系统内部加了:这四个requestChecker。但是加入到里面的requestChecker,会执行他们的acceptRequest方法,如果返回false,那么就会调用它的checkRequest来处理,如果返回true是不会调用它的checkRequest方法的。
经过上面拦截器的运行,如果其中有哪个interceptor的preHandle返回false了,请求就不往后执行了。
如果返回true,就继续执行,当执行到mappedHandler.applyPostHandle(processedRequest, response, mv);时,又会调用那些intecertor的postHandle来处理请求。
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors;
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
大部分intercetor的postHandle方法都是空方法。,所以intercetor主要用来预处理请求的。