spring boot: filter/interceptor/aop在獲取request/method引數上的區別(spring boot 2.3.1)
一,filter/interceptor/aop在獲取引數上有什麼區別?
1,filter可以修改HttpServletRequest的引數(doFilter方法的功能),
interceptor/aop都沒有這個功能
但它不提供到被過濾的方法的訪問
注意區分請求request的方法
2, interceptor能得到所攔截的方法名和引數名,
不能得到引數值
3, aspect能得到註解所在方法的方法名和引數名、引數值,
還可以修改方法的引數值
另外:
filter/interceptor都是針對請求,
aop則是針對方法
看程式碼,有更直觀的感受
說明:劉巨集締的架構森林是一個專注架構的部落格,地址:
對應的原始碼可以訪問這裡獲取:https://github.com/liuhongdi/
說明:作者:劉巨集締 郵箱: [email protected]
二,演示專案的相關資訊
1,專案地址
https://github.com/liuhongdi/filterinterceptoraop
2,專案原理:
我們在controller中的一個方法上,
添加了filter/interceptor/aspect
然後比較我們能得到哪些引數,對引數做哪些處理?
3,專案結構:
如圖:
三,java程式碼說明:
1,ParamFilter.java
@Component public class ParamFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("----------------filter init"); } //過濾功能 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("----------------filter doFilter begin"); //列印得到的request引數 Enumeration paramNames = servletRequest.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = (String) paramNames.nextElement(); String[] paramValues = servletRequest.getParameterValues(paramName); if (paramValues.length == 1) { String paramValue = paramValues[0]; if (paramValue.length() != 0) { System.out.println("[filter] request parameter name:"+paramName+";value:"+paramValue); } } } //修改請求引數 HashMap m = new HashMap(servletRequest.getParameterMap()); m.put("newp", new String[] { "abcd" }); m.put("v", new String[] { "filterv" }); HttpServletRequest req = (HttpServletRequest) servletRequest; CustomRequestWrapper wrapRequest = new CustomRequestWrapper(req, m); servletRequest = wrapRequest; filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("----------------filter destroy"); } }
說明:filter中可以修改request引數,
但不能對方法進行訪問
2,ValidateorInterceptor.java
@Component public class ValidatorInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("---------------interceptor begin"); //列印request引數 Enumeration<?> temp = request.getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String) temp.nextElement(); String value = request.getParameter(en); System.out.println("[interceptor] request parameters: name:"+en+";value:"+value); } } //列印method的相關資訊 if(handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 獲取處理當前請求的 handler 資訊 System.out.println("[interceptor] method 類名:" + handlerMethod.getBeanType().getName()); System.out.println("[interceptor] method 方法:" + handlerMethod.getMethod().getName()); MethodParameter[] methodParameters = handlerMethod.getMethodParameters(); for (MethodParameter methodParameter : methodParameters) { // 只能獲取引數的名稱,type,index,不能獲取到引數的值 System.out.println("[interceptor] method parameter Name: " + methodParameter.getParameterName()); System.out.println("[interceptor] method parameter Type: " + methodParameter.getParameterType()); System.out.println("[interceptor] method parameter Index: " + methodParameter.getParameterIndex()); } } //sign校驗無問題,放行 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
說明:interceptor中,只能得到方法的引數名,不能得到引數值
3,RedisRateLimiterAspect.java
@Component @Aspect public class RedisRateLimiterAspect { @Pointcut("@annotation(com.filterinterceptoraop.demo.annotation.RedisRateLimiter)") private void pointcut() {} /* * around, * if reach limit in time * return error info * */ @Around(value = "pointcut()") public Object requestLimit(ProceedingJoinPoint joinPoint) throws Exception { System.out.println("---------------aop begin"); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); //列印request引數 Enumeration<?> temp = request.getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String) temp.nextElement(); String value = request.getParameter(en); System.out.println("[aop] request parameter name:"+en+";value:"+value); } } //列印方法的資訊 Object[] args = joinPoint.getArgs(); try { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature)signature; //獲取目標方法 Method targetMethod = methodSignature.getMethod(); String method_name = targetMethod.getName(); System.out.println("[aop] method name:"+method_name); String[] paramNames = methodSignature.getParameterNames(); Map<String, Object> nameAndArgs = new HashMap<String, Object>(); for (int i = 0; i < paramNames.length; i++) { nameAndArgs.put(paramNames[i], args[i]);// paramNames即引數名 if (paramNames[i].equals("version")) { //System.out.println("version value:"+args[i]); args[i] = "aopv"; } System.out.println("[aop] method parameter name:"+paramNames[i]+";value:"+args[i]); } if (targetMethod.isAnnotationPresent(RedisRateLimiter.class)) { return joinPoint.proceed(args); } else { return joinPoint.proceed(); } } catch (Throwable e) { e.printStackTrace(); return null; } } }
說明:aop中,可以得到方法的引數名和引數值,而且還可以修改方法的引數值
四,測試效果
1,訪問url:
http://127.0.0.1:8080/home/home?v=1
然後檢視控制檯的輸出
2,filter的輸出
----------------filter doFilter begin [filter] request parameter name:v;value:1
filter中我們得到了正確的request引數值
3,interceptor的輸出
---------------interceptor begin [interceptor] request parameters: name:v;value:filterv [interceptor] request parameters: name:newp;value:abcd [interceptor] method 類名:com.filterinterceptoraop.demo.controller.HomeController [interceptor] method 方法:homeMethod [interceptor] method parameter Name: version [interceptor] method parameter Type: class java.lang.String [interceptor] method parameter Index: 0 [interceptor] method parameter Name: httpServletRequest [interceptor] method parameter Type: interface javax.servlet.http.HttpServletRequest [interceptor] method parameter Index: 1 [interceptor] method parameter Name: httpServletResponse [interceptor] method parameter Type: interface javax.servlet.http.HttpServletResponse [interceptor] method parameter Index: 2 [interceptor] method parameter Name: modelMap [interceptor] method parameter Type: class org.springframework.ui.ModelMap [interceptor] method parameter Index: 3
請求引數v的值變成了filterv,而且增加了一個請求引數:newp,
這是filter中程式碼的作用
可以看到:interceptor得到了它所攔截請求對應的方法名和引數名,
但沒有方法的引數值,它也不能修改request的引數和方法的引數
4,aop的輸出:
---------------aop begin
[aop] request parameter name:v;value:filterv
[aop] request parameter name:newp;value:abcd
[aop] method name:homeMethod
[aop] method parameter name:version;value:aopv
[aop] method parameter name:httpServletRequest;value:com.filterinterceptoraop.demo.wrapper.CustomRequestWrapper@1ce466d8
[aop] method parameter name:httpServletResponse;value:org.apache.catalina.connector.ResponseFacade@45eedc13
[aop] method parameter name:modelMap;value:{}
aop中的請求引數沒有變,
它可以得到方法的引數名和引數值,
在這裡我們修改引數version的值為 aopv
5,controller中的輸出:
---------------controller begin
[controller] request parameter name:v;value:filterv
[controller] request parameter name:newp;value:abcd
[controller] method parameter version:aopv
controller中接收到的方法的引數值是我們在aop中修改過的
五,檢視spring boot版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE)