自定义过滤器,只要实现Filter接口,并添加@Component注解即可
@Component public class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("time filter init"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("time filter start"); long startTime = System.currentTimeMillis(); chain.doFilter(request, response); System.out.printf("耗时:%d \r\n", System.currentTimeMillis() - startTime); System.out.println("time filter finish"); } @Override public void destroy() { System.out.println("time filter destroy"); } }
添加第三方过滤器,在配置类(@Configuration)中添加注入一个Bean(FilterRegistrationBea),指定生效路径
@Configuration public class WebConfig { @Bean public FilterRegistrationBean<TimeFilter> timeFilter(){ FilterRegistrationBean<TimeFilter> registrationBean = new FilterRegistrationBean<>(); // 设置过滤器 TimeFilter timeFilter = new TimeFilter(); registrationBean.setFilter(timeFilter); // 声明起作用的请求地址 List<String> urls = new ArrayList<>(16); urls.add("/user/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }
在过滤器中只能获取到http请求数据,不能识别那个控制器处理当前请求
需要实现HandlerInterceptor接口,并在配置类中进行注册
a.创建类,实现HandlerInterceptor接口,注册为一个组件(@Component)
@Component public class TimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 调用控制器之前 System.out.println("preHandle"); request.setAttribute("startTime", System.currentTimeMillis()); System.out.println(((HandlerMethod)handler).getBean().getClass().getName()); System.out.println(((HandlerMethod)handler).getMethod().getName()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 调用控制器正常返回之后(异常时不调用) System.out.println("postHandle"); Long startTime = (Long)request.getAttribute("startTime"); System.out.println("postHandle Interceptor 耗时:" + (System.currentTimeMillis() - startTime)); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 调用控制器返回之后 System.out.println("afterCompletion"); Long startTime = (Long)request.getAttribute("startTime"); System.out.println("afterCompletion Interceptor 耗时:" + (System.currentTimeMillis() - startTime)); } }
b.配置类(@Configuration) 继承 WebMvcConfigurer接口,覆盖addInterceptors方法,用registry.addInterceptor(timeInterceptor) 添加拦截器
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private TimeInterceptor timeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor); } @Bean public FilterRegistrationBean<TimeFilter> timeFilter(){ FilterRegistrationBean<TimeFilter> registrationBean = new FilterRegistrationBean<>(); TimeFilter timeFilter = new TimeFilter(); registrationBean.setFilter(timeFilter); List<String> urls = new ArrayList<>(16); urls.add("/user/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }
控制台打印
time filter start preHandle com.yui.study.security.demo.controller.UserController getUserInfor postHandle postHandle Interceptor 耗时:435 afterCompletion afterCompletion Interceptor 耗时:440 time filter 耗时:466 time filter finish
无法获取到调用方法的参数
handler可以获取访问的控制器的声明,为HandlerMethod实例 Exception ex 获取发生的异常
@Aspect 注解,声明作用范围(@Around)
@Aspect @Component public class TimeAspect { @Around("execution(* com.yui.study.security.demo.controller.UserController.*(..))") public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("aspect begin"); long start = System.currentTimeMillis(); // 获取参数 for (Object arg : pjp.getArgs()) { System.out.println("arg is " + arg); } Object o = pjp.proceed(); System.out.println("aspect end"); System.out.println("aspect 耗时:"+(System.currentTimeMillis() - start)); return o; } }
控制台打印
time filter start preHandle com.yui.study.security.demo.controller.UserController$$EnhancerBySpringCGLIB$$2b45dbcf getUserInfor aspect begin arg is 1 aspect end aspect 耗时:6 postHandle postHandle Interceptor 耗时:342 afterCompletion afterCompletion Interceptor 耗时:348 time filter 耗时:375 time filter finish
@Before() 调用方法之前 @After() 调用方法之后 @AfterThrowing 异常时 @Around() 包含上述三种,一般使用这个
详情可参考 spring-framework官方文档 例子说明
execution(* com.yui.study.security..*.*(..)) execution(): 表达式的主体asdFG 第一个“*”符号:表示返回值的类型任意 com.yui.study.security: AOP所切的服务的包名,即,需要进行横切的业务类 包名后面的“..”:表示当前包及子包 第二个“*”:表示类名,*即所有类 .*(..):表示任何方法名,括号表示参数,两个点表示任何参数类型
获取不到原始的http请求
调用顺序 filter -> Interceptor -> ControllerAdvice -> Aspect -> controllermark text
controller
@RestController public class AsyncController { private Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping("/order") public String test() throws InterruptedException { logger.info("主线程开始"); Thread.sleep(10000); logger.info("主线程结束"); return "SUCCESS"; } @RequestMapping("/orderAsync") public Callable<String> test02() { logger.info("主线程开始"); Callable<String> result = () -> { logger.info("副线程开始"); Thread.sleep(10000); logger.info("副线程结束"); return "SUCCESS"; }; logger.info("主线程结束"); return result; } }
测试异步日志打印
2018-12-06 15:22:08.137 INFO 14540 --- [nio-8081-exec-2] c.y.s.s.demo.async.AsyncController : 主线程开始 2018-12-06 15:22:08.137 INFO 14540 --- [nio-8081-exec-2] c.y.s.s.demo.async.AsyncController : 主线程结束 2018-12-06 15:22:08.140 WARN 14540 --- [nio-8081-exec-2] o.s.w.c.request.async.WebAsyncManager : !!! An Executor is required to handle java.util.concurrent.Callable return values. Please, configure a TaskExecutor in the MVC config under "async support". The SimpleAsyncTaskExecutor currently in use is not suitable under load. ------------------------------- Request URI: '/orderAsync' !!! 2018-12-06 15:22:08.145 INFO 14540 --- [ MvcAsync1] c.y.s.s.demo.async.AsyncController : 副线程开始 2018-12-06 15:22:09.419 INFO 14540 --- [nio-8081-exec-4] c.y.s.s.demo.async.AsyncController : 主线程开始 2018-12-06 15:22:09.419 INFO 14540 --- [nio-8081-exec-4] c.y.s.s.demo.async.AsyncController : 主线程结束 2018-12-06 15:22:09.421 INFO 14540 --- [ MvcAsync2] c.y.s.s.demo.async.AsyncController : 副线程开始 2018-12-06 15:22:18.146 INFO 14540 --- [ MvcAsync1] c.y.s.s.demo.async.AsyncController : 副线程结束 2018-12-06 15:22:19.422 INFO 14540 --- [ MvcAsync2] c.y.s.s.demo.async.AsyncController : 副线程结束
警告内容是需要一个线程池来处理多线程
@Configuration public class WebConfig implements WebMvcConfigurer { private ThreadPoolTaskExecutor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(30); executor.setQueueCapacity(100); executor.setThreadNamePrefix("ronnie-task-"); executor.initialize(); return executor; } @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(getAsyncExecutor()); WebMvcConfigurer.super.configureAsyncSupport(configurer); } }
@Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(getAsyncExecutor()); configurer.registerCallableInterceptors(); configurer.registerDeferredResultInterceptors(); WebMvcConfigurer.super.configureAsyncSupport(configurer); }
pom.xml
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
程序入口添加 @EnableSwagger2 注解
@SpringBootApplication @EnableSwagger2 public class DemoApplication { /** * 启动入口 * @param args */ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@ApiModelProperty("用户id") : 参数为对象时使用,注解在对象的属性上 @ApiParam("用户id") : 参数为基本数据类型是使用,注解在参数前,如:
public User getUserInfor(@ApiParam("用户id") @PathVariable Long id){ ... }
@ApiOperation("用户信息查询服务") 注解在方法上,修改方法默认名称
本文作者:Yui_HTT
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!