自定义注解、AOP实例

2020-06-26  本文已影响0人  lbcBoy

目录
一、学习自定义注解
二、自己编写一个注解,并在controller上使用这个注解,看一下5种通知类型的调用顺序。
三、过滤器、拦截器、AOP的区别

一、学习自定义注解

自定义注解常用在日志,权限,加密等场景下。
我们使用最常见的@SpringbootApplication,看一下注解的定义中会用到哪些注解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

二、自己编写一个注解,并在controller上使用这个注解,看一下5种通知类型的调用顺序。

MyAnnotation.java(我自定义的一个测试注解)

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public  @interface MyAnnotation {
    String value() default "";
}

MyAnnotationInterceptor.java(自定义测试注解的拦截器)

/**
 * MyAnnotation注解对应的拦截器
 * AspectJ 支持 5 种类型的通知注解:
 *
 * @Before: 前置通知, 在方法执行之前执行
 * @After: 后置通知, 在方法执行之后执行
 * @AfterRunning: 返回通知, 在方法返回结果之后执行
 * @AfterThrowing: 异常通知, 在方法抛出异常之后
 * @Around: 环绕通知, 围绕着方法执行
 **/
@Component
@Aspect
public class MyAnnotationInterceptor {
    public static final Logger logger = LoggerFactory.getLogger(MyAnnotationInterceptor.class);

    @Pointcut("@annotation(com.lbc.demo.aop.MyAnnotation)")
    public void functionAspect() {

    }

    @Around(value = "functionAspect()")
    public void doAround(ProceedingJoinPoint pjp) throws Throwable {
        logger.info("around执行方法之前");
        Object object = pjp.proceed();
        logger.info("around执行方法之后--返回值:" + object);
    }

    @Before("functionAspect()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("doBefore");
    }

    @After("functionAspect()")
    public void doAfter(JoinPoint joinPoint) {
        logger.info("doAfter");
    }

    @AfterReturning(returning = "returnObj", pointcut = "functionAspect()")
    public void doAfterReturning(JoinPoint joinPoint, Object returnObj) {
        logger.info("AfterReturning");
    }

    @AfterThrowing(value = "functionAspect()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        logger.info("AfterThrowing");
    }
}
执行结果:
image.png
直接放结论:
@Order注解的作用:
@Inherited注解的作用:

过滤器、拦截器、AOP的区别

过滤器
过滤器可以拦截到方法的请求和响应(ServletRequest request, SetvletResponse response),
并对请求响应做出响应的过滤操作,比如设置字符编码、鉴权操作。
拦截器
Spring中拦截器有三个方法:preHandle,postHandle,afterCompletion。
public boolean preHandle(HttpServletRequest httpServletRequest, 
HttpServletResponse httpServletResponse, Object o)
表示被拦截的URL对应的方法执行前的自定义处理

public void postHandle(HttpServletRequest httpServletRequest, 
HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
表示此时还未将modelAndView进行渲染,被拦截的URL对应的方法执行后的自定义处理,。

public void afterCompletion(HttpServletRequest httpServletRequest, 
HttpServletResponse httpServletResponse, Object o, Exception e)
表示此时modelAndView已被渲染,执行拦截器的自定义处理。
AOP切片
AOP操作可以对操作进行横向的拦截,最大的优势在于可以获取执行方法的参数,对方法进行统一的处理,常见使用日志,事务,请求参数安全验证等。

顺序
请求->>过滤器->>拦截器-->Aspect->>拦截器->>过滤器->>响应

三者使用场景类似
**从过滤器--》拦截器--》切面,拦截规则越来越细致,执行顺序依次是过滤器、拦截器、切面。**
一般情况下数据被过滤的时机越早对服务的性能影响越小,因此我们在编写相对比较公用的代码时,优先考虑过滤器,然后是拦截器,最后是aop。
比如权限校验,一般情况下,所有的请求都需要做登陆校验,此时就应该使用过滤器在最顶层做校验;日志记录,一般日志只会针对部分逻辑做日志记录,
而且牵扯到业务逻辑完成前后的日志记录,因此使用过滤器不能细致地划分模块,此时应该考虑拦截器,
然而拦截器也是依据URL做规则匹配,因此相对来说不够细致,因此我们会考虑到使用AOP实现,AOP可以针对代码的方法级别做拦截,很适合日志功能。

参考:https://www.jianshu.com/p/8cbfff715581
https://zhuanlan.zhihu.com/p/96597358
https://blog.csdn.net/u011277123/article/details/91532149
https://www.jianshu.com/p/7f54e7250be3
https://www.cnblogs.com/natian-ws/p/10824363.html
https://www.cnblogs.com/quartz/p/12601091.html

上一篇 下一篇

猜你喜欢

热点阅读