SpringAOP使用

一、AOP介绍

AOP ,面向切面编程,在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。其实就是在代码运行,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理

先讲一下AspectJ和Spring AOP关系,网上很多文章对AspectJ存在错误说法

AspectJ:

  • AspectJ 来自于 Eclipse 基金会,是Eclipse托管给Apache基金会的一个开源项目
  • 属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:
    • Compile-time weaving:编译期织入
    • Post-compile weaving:也就是已经生成了 .class 文件,就要用到编译后织入
    • Load-time weaving:指的是在加载类的时候进行织入
  • AspectJ框架非常强大,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入)
  • AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的

SpringAOP:

  • 基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现
  • Spring AOP 和AspectJ并没有什么太多的关系,仅仅是Spring 延用了 AspectJ 中的概念,包括使用了 AspectJ 提供的 jar 包中的注解,但是不依赖于其实现功能
  • Spring AOP 需要依赖于 IOC 容器来管理,只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法
  • Spring AOP 比 AspectJ 的性能稍差

二、Spring AOP术语解释

Joinpoint(连接点)
所谓连接点是指能够被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点(任何一个方法都可以称为连接点)

Pointcut(切入点)
切入点是指我们要对哪些Joinpoint进行拦截的定义(对哪个方法进行增强)

Advice(通知/增强)
通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)(要给它增加什么功能)

Target(目标对象)
代理的目标对象

Weaving(织入)
是指把增强应用到目标对象来创建新的代理对象的过程(怎样得到代理对象)

Proxy(代理)
一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面)
是切入点和通知的结合,构成切面,我们可以使用注解或者xml进行配置

三、Spring AOP注解使用

1. 在 xml 中配置
开启 @AspectJ 的注解,还有其它方式,这里不介绍

<aop:aspectj-autoproxy/>

2. 使用@Aspect注解
定义实现AOP的配置类
@Aspect 注解要作用在 bean 上面

@Component
@Aspect
public class LogAspect {
}

3. 配置 Pointcut
用于定义哪些方法需要被增强或者说需要被拦截

    @Pointcut(""execution(* com.ljj.service(..))"")
    private void controllerAspect() {
        // TODO Auto-generated method stub
    }
    
     
    @Pointcut("@annotation(com.ljj.annotation.Log)")
    private void controllerAspect1() {
        // TODO Auto-generated method stub
    }
	
	
    @Pointcut(""within(com.ljj.service..*)"")
    private void controllerAspect2() {
        // TODO Auto-generated method stub
    }
    
    @Pointcut("bean(*Service)")
    private void controllerAspect3() {
        // TODO Auto-generated method stub
    }
  • execution ,正则匹配方法签名
  • @annotation。匹配对应注解的方法
  • within,指定所在类或所在包下面的方法
  • bean(idOrNameOfBean), 匹配 bean 的名字

4. 配置 Advice

   @Aspect
public class AdviceExample {

    // 下面方法就是写拦截 "dao层实现"
    @Before("com.ljj.aop.dataAccessOperation()")
    public void doAccessCheck() {
        // ... 实现代码
    }

    @Before("execution(* com.ljj.dao.*.*(..))")
    public void doAccessCheck() {
        // ... 实现代码
    }

    @AfterReturning("com.ljj.aop.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }

    @AfterReturning(
        pointcut="com.ljj.aop.dataAccessOperation()",
        returning="retVal")
    public void doAccessCheck(Object retVal) {
        // 这样,进来这个方法的处理时候,retVal 就是相应方法的返回值,是不是非常方便
        //  ... 实现代码
    }

    // 异常返回
    @AfterThrowing("com.ljj.aop.dataAccessOperation()")
    public void doRecoveryActions() {
        // ... 实现代码
    }

    @AfterThrowing(
        pointcut="com.ljj.aop.dataAccessOperation()",
        throwing="ex")
    public void doRecoveryActions(DataAccessException ex) {
        // ... 实现代码
    }

    // 注意理解它和 @AfterReturning 之间的区别,这里会拦截正常返回和异常的情况
    @After("com.ljj.aop.dataAccessOperation()")
    public void doReleaseLock() {
        // 通常就像 finally 块一样使用,用来释放资源。
        // 无论正常返回还是异常退出,都会被拦截到
    }

    // 既能做 @Before 的事情,也可以做 @AfterReturning 的事情
    @Around("com.ljj.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }
}

上面Advice都已经匹配了对应的PointCut,这样定义可以不用再定义PointCut了。也可以使用下面这种PointCut + Advice

	//定义日志注解
    @Target({ ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Log {

    //操作名
    String optName();

    //操作类型
    OperateType optType();

    //操作表名
    String optTable();

    //操作编码
    String optCode();
  }


   @Pointcut("@annotation(com.ljj.annotation.Log)")
    private void controllerAspect() {
        // TODO Auto-generated method stub
    }
	
	//日志切面
    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
       try {
       		//方法执行前操作
            result = point.proceed();
            //方法执行后操作
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值