AOP(面向切面编程)

AOP(面向切面编程)

1、概念

1.1 什么是AOP

AOP(Aspect Orient Programming) : 面向切面编程

Aspect :表示切面, 给业务方法增加的功能,叫做切面。 切面一般都是非业务功能, 而且切面功能一般都是可以复用的。 例如 日志功能, 事务功能, 权限检查,参数检查, 统计信息等等。

Orient:面向,对着

Programming:编程。

怎么理解面向切面编程 ? 以切面为核心设计开发你的应用。

1)设计项目时, 找出切面的功能。

2)安排切面的执行时间, 执行的位置。

1.2 AOP作用

1)让切面功能复用

2)让开发人员专注业务逻辑。 提高开发效率

3)实现业务功能和其他非业务功能解耦合。

4)给存在的业务方法, 增加功能,不用修改原来的代码

1.3 AOP中术语

1)Aspect:切面, 给业务方法增加的功能**\(即增强方法)**。

2)JoinPoint:连接点, 连接切面的业务方法。 在这个业务方法执行时,会同时执行切面的功能。

3)Pointcut: 切入点, 是一个或多个连接点集合。 表示这些方法执行时,都能增加切面的功能**\( 即对哪些业务方法进行增强)**。

​ 表示切面执行的位置。

4)target: 目标对象, 给那个对象增加切面的功能, 这个对象就是目标对象。

5)Advice:通知(增强),表示切面的执行时间。 在目标方法之前执行切面,还是目标方法之后执行切面。

AOP中重要的三个要素: Aspect, Pointcut , Advice. 这个概念的理解是: 在Advice的时间,在Pointcut的位置, 执行Aspect

AOP是一个动态的思想。 在程序运行期间,创建代理(ServcieProxy),使用代理执行方法时,增加切面的功能。这个代理对象是存在内存中的。

2、Aspectj框架实现AOP

2.1 通知

Aspectj表示切面执行时间,用的通知(Advice)。 这个通知可以使用注解表示。

讲5个注解, 表示切面的5个执行时间, 这些注解叫做通知注解。

@Before : 前置通知

@AfterRetunring: 后置通知

@Around: 环绕通知

@AfterThrowing:异常通知

@After:最终通知

@Pointcut定义和管理切入点注解(这个不是通知)

2.2 Pointcut 位置

Pointcut 用来表示切面执行的位置, 使用Aspectj中切入点表达式(即你要在那个目标方法上增强)。

切入点表达式语法: execution(访问权限 方法返回值 方法声明(参数) 异常类型)

2.3 Aspectj的注解使用

(1)@Before前置通知

前置通知@Before

/**
 * 切面类中的通知方法,可以有参数
 * JoinPoint必须是他。
 *
 * JoinPoint: 表示正在执行的业务方法。 相当于反射中 Method
 *   使用要求:必须是参数列表的第一个
 *   作用:获取方法执行时的信息,例如方法名称, 方法的参数集合
 */
@Before(value = "execution(* *..SomeServiceImpl.do*(..) )")
public void myBefore2(JoinPoint jp){

    //获取方法的定义
    System.out.println("前置通知中,获取目标方法的定义:"+jp.getSignature());
    System.out.println("前置通知中,获取方法名称="+jp.getSignature().getName());
    //获取方法执行时参数
    Object args []= jp.getArgs();// 数组中存放的是 方法的所有参数
    for(Object obj:args){
        System.out.println("前置通知,获取方法的参数:"+obj);
    }

    String methodName = jp.getSignature().getName();
    if("doSome".equals(methodName)){
        //切面的代码。
        System.out.println("doSome输出日志=====在目标方法之前先执行==:"+ new Date());
    } else if("doOther".equals(methodName)){
        System.out.println("doOther前置通知,作为方法名称,参数的记录。");
    }

}
(2)@AfterReturning后置通知

@AfterReturning: 在目标方法之后执行的

 /* 特点:
     *  1.在目标方法之后,执行的。
     *  2.能获取到目标方法的执行结果。
     *  3.不会影响目标方法的执行
     *
     * 方法的参数:
     *   Object res: 表示目标方法的返回值,使用res接收doOther的调用结果。
     *   Object res= doOther();
     *
     *  后置通知的执行顺序
     *  Object res = SomeServiceImpl.doOther(..); Student
     *
     *  myAfterReturning(res);
     *
     *  思考:
     *    1 doOther方法返回是String ,Integer ,Long等基本类型,
     *      在后置通知中,修改返回值, 是不会影响目标方法的最后调用结果的。
     *    2 doOther返回的结果是对象类型,例如Student。
     *      在后置通知方法中,修改这个Student对象的属性值,会不会影响最后调用结果?
     */
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",
                    returning = "res")
    public void myAfterReturning(JoinPoint jp, Object res){

        //修改目标方法的返回值
        if(res != null){
            res = "HELLO Aspectj";
        }
        System.out.println("后置通知,在目标方法之后,执行的。能拿到执行结果:"+res);
        //Object res有什么用
        if("abcd".equals(res)){
            System.out.println("根据返回值的不同,做不同的增强功能");
        } else if("add".equals(res)){
           System.out.println("doOther做了添加数据库, 我做了备份数据");
        }


    }
(3)@Around 环绕通知

@Around(value=“切入点表达式”)

使用环绕通知: 就是调用 切面类中的通知方法。

/**
 * @Around:环绕通知
 *    属性:value 切入点表达式
 *    位置:在方法定义的上面
 *
 * 返回值:Object ,表示调用目标方法希望得到执行结果(不一定是目标方法自己的返回值)
 * 参数:  ProceedingJoinPoint, 相当于反射中 Method。
 *        作用:执行目标方法的,等于Method.invoke()
 *
 *        public interface ProceedingJoinPoint extends JoinPoint {}
 *
 * 特点:
 *  1.在目标方法的前和后都能增强功能
 *  2.控制目标方法是否执行
 *  3.修改目标方法的执行结果。
 */
@Around("execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

    //获取方法执行时的参数值
    String name = "";
    Object args [] = pjp.getArgs();
    if( args != null && args.length > 0){
        Object arg = args[0];
        if(arg !=null){
            name=(String)arg;
        }
    }

    Object methodReturn = null;

    System.out.println("执行了环绕通知,在目标方法之前,输出日志时间=="+ new Date());
    //执行目标方法  ProceedingJoinPoint,表示doFirst

    if("lisi".equals(name)){
        methodReturn = pjp.proceed();
        //method.invoke(),表示执行doFirst()方法本身
    }

    if( methodReturn != null){
        methodReturn ="环绕通知中,修改目标方法原来的执行结果";
    }

    System.out.println("环绕通知,在目标方法之后,增加了事务提交功能");

    //return "HelloAround,不是目标方法的执行结果";
    //返回目标方法执行结果。没有修改的。
    return methodReturn;

}
(4) @AfterThrowing 异常通知

语法@AfterThrowing(value=“切入点表达式”,throwing=“自定义变量”)

/**
 * @AfterThrowing:异常通知
 *     属性: value 切入点表达式
 *           throwing 自定义变量,表示目标方法抛出的异常。
 *                    变量名必须和通知方法的形参名一样
 *     位置:在方法的上面
 * 特点:
 *  1. 在目标方法抛出异常后执行的, 没有异常不执行
 *  2. 能获取到目标方法的异常信息。
 *  3. 不是异常处理程序。可以得到发生异常的通知, 可以发送邮件,短信通知开发人员。
 *      看做是目标方法的监控程序。
 *
 *  异常通知的执行
 *  try{
 *      SomeServiceImpl.doSecond(..)
 *  }catch(Exceptoin e){
 *      myAfterThrowing(e);
 *  }
 */
@AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",throwing = "ex")
public void myAfterThrowing(Exception ex){
    System.out.println("异常通知,在目标方法抛出异常时执行的,异常原因是:"+ex.getMessage());
    /*
       异常发生可以做:
       1.记录异常的时间,位置,等信息。
       2.发送邮件,短信,通知开发人员
     */
}
(5) @After 最终通知

语法: @After(value=“切入点表达式”)

/**
 * @After:最终通知
 *    属性: value 切入点表达式
 *    位置: 在方法的上面
 * 特点:
 *  1. 在目标方法之后执行的。
 *  2. 总是会被执行。
 *  3. 可以用来做程序最后的收尾工作。例如清除临时数据,变量。 清理内存
 *
 *  最终通知
 *  try{
 *      SomeServiceImpl.doThird(..)
 *  }finally{
 *      myAfter()
 *  }
 */
@After(value = "execution(* *..SomeServiceImpl.doThird(..))")
public void myAfter(){
    System.out.println("最终通知,总是会被执行的");
}
(6) @Pointcut定义和管理切入点注解

@Pointcut(value=“切入点表达式”)

@After(value = "mypt()")
public void myAfter(){
    System.out.println("最终通知,总是会被执行的");
}


/**
 * @Pointcut: 定义和管理切入点,不是通知注解。
 *     属性: value 切入点表达式
 *     位置: 在一个自定义方法的上面, 这个方法看做是切入点表达式的别名。
 *           其他的通知注解中,可以使用方法名称,就表示使用这个切入点表达式了
 */
@Pointcut("execution(* *..SomeServiceImpl.doThird(..))")
private void mypt(){
    //无需代码
}

2.4、AOP总结

​ AOP是一种动态的技术思想, 目的是实现业务功能和非业务功能的解耦合。 业务功能是独立的模块, 其他功能也是独立的模块。例如事务功能,日志等等。 让这些事务,日志功能是可以被复用的。

​ 当目标方法需要一些功能时,可以在不修改,不能修改源代码的情况下, 使用aop技术在程序执行期间,生成代理对象, 通过代理执行业务方法,同时增加功能。

3、AOP实战

AOP日志

项目是基于SpringBoot编写的,整体代码在下一篇文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值