Spring Aop 简单入门应用

Spring Aop 简单入门应用

1.Aop切面概念

  • 作用意图

    面向切面编程(Aspect Oriented Programming),在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待

    将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

  • 基本概念

    1 Aspect(切面):通常是一个类,里面可以定义切入点和通知

    2 JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

    3 Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning, afterThrowing,around

    4 Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

    5 AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动 态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

2.Spring Aop

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

  • 默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

  • 当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

基于注解的AOP配置方式(使用xml的配置这里不作叙述)

1 通知类型介绍

  • Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

  • AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

  • AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象

  • After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

  • Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

2 通知执行的优先级

  进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。

  注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。

3 切入点的定义和表达式

  切入点表达式的定义算是整个AOP中的核心,有一套自己的规范

  Spring AOP支持的切入点指示符:

  • execution:用来匹配执行方法的连接点

    @Pointcut(“execution(* com.demo.springaop.service….(…))”)

    第一个*表示匹配任意的方法返回值,…(两个点)表示零个或多个,上面的第一个…表示service包及其子包,第二个*表示所有类,第三个*表示所有方法,第二个…表示方法的任意参数个数

  • within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点

    @Pointcut(“within(com.demo.springaop.service.*)”)

  • this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService

    @Pointcut(“this(com.demo.springaop.service.UserService)”)

  • bean也是非常常用的,bean可以指定IOC容器中的bean的名称

    @Pointcut(“bean(userService)”)

概念说的再好,不如实际运用

1 准备依赖包

<!-- spring框架aop支持 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.0.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
<!-- 下面这个包也是aop需要的包,但是经测试 不要这个包也可以 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.4</version>
</dependency>

注意:如果启动报错如下错,
  error at ::0 can't find referenced pointcut serviceLogAspect
一般是因为aspectjweaver包与jdk版本冲突的问题导致的。
1.9.4版本支持JDK1.8  如果是低版本的JDK使用aspectjweaver低一点的版本

2 首页要启用@AsjectJ支持 在项目中的context.xml加入以下配置(实际项目中可能叫applicationContext.xml,根据自己项目即可)

<!-- 启用注解  -->
<context:annotation-config />

<!-- 配置注解扫描包 -->
<context:component-scan base-package="com.demo.springaop"/>

<!-- 启用@AsjectJ支持 -->
<aop:aspectj-autoproxy />

3 代码案例

@Component
@Aspect
@Slf4j(topic = "bizLogger")
public class SoLoggerAspect {

    @Pointcut("execution(* com.demo.springaop.service..*.*(..))")
    public void serviceLogAspect() {

    }

    @Before("serviceLogAspect()")
    public void before(JoinPoint jp) {
        try {
            log.info("Aop before ["+jp.getSignature().toShortString()+"] ");
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法执行结束
     * @param jp
     * @param o 是返回出参
     */
    @AfterReturning(pointcut = "serviceLogAspect()", returning = "o")
    public void afterReturning(JoinPoint jp, Object o) {
        log.info("Aop afterReturning ["+jp.getSignature().toShortString()+"] ");
    }
    
//已使用环绕通知
//    @AfterThrowing(pointcut = "serviceLogAspect()", throwing = "t")
//    public void AfterThrowing(JoinPoint jp, Throwable t) {
//        log.error("Aop AfterThrowing ["+jp.getSignature().toShortString()+"] "+ t.toString());
//    }

    /**
     * 统计方法执行耗时Around环绕通知
     * @param joinPoint
     * @return
     */
    @Around("serviceLogAspect()")
    public Object timeAround(ProceedingJoinPoint joinPoint) {
        //定义返回对象、得到方法需要的参数
        Object obj = null;
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();

        try {
            obj = joinPoint.proceed(args);
        } catch (Throwable e) {
            log.error("Aop Around error ["+joinPoint.getSignature().toShortString()+"]"+(e.getMessage() == null? e.toString(): e.getMessage()));
        }
        long endTime = System.currentTimeMillis();
        long diffTime = endTime - startTime;
        //超过1秒打印耗时
        if (diffTime > 1000) {
            log.info("run time ["+joinPoint.getSignature().toShortString()+"] 耗时:" + diffTime + " :ms");
        }
        return obj;
    }


4 运行效果参考,对于日志的打印直接换成自己的即可。

2019-06-13 11:21:50 -·- INFO  -·- Aop before  [UserService.getUserList(..)]
2019-06-13 11:21:51 -·- INFO  -·- run time [UserService.getUserList(..)] 耗时:1004 :ms 
2019-06-13 11:21:51 -·- INFO  -·- Aop afterReturning [UserService.getUserList(..)] 
2019-06-13 11:21:57 -·- INFO  -·- Aop before [UserService.getUserById(..)] 
2019-06-13 11:21:57 -·- INFO  -·- Aop afterReturning [UserService.getUserById(..)] 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WEB届的阿猫阿狗

即使没有奖励,我也不会停下脚步

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值